From patchwork Wed Aug 24 11:59:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56977 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 E6FDF3851143 for ; Wed, 24 Aug 2022 12:00:32 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x42d.google.com (mail-wr1-x42d.google.com [IPv6:2a00:1450:4864:20::42d]) by sourceware.org (Postfix) with ESMTPS id ECB8738515FE; Wed, 24 Aug 2022 12:00:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org ECB8738515FE Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x42d.google.com with SMTP id d16so15193771wrr.3; Wed, 24 Aug 2022 05:00:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=vW+oVBrKyKiiJASPTJ3TiwNitoa8EthpxoFCyHSWd/o=; b=UQJmvI3KyD1FHqQGGgXTd3E760BXBudHrBqMy0xQOaObKcv9mKQgVsGcqPE7+6o8Iz ANy50eyUDeqxtUIGPtt6fwtmRCi1QJ0GdqT4gcwWC1oHeYlGBCSYRIOuaSyCnwuWLYt5 8TgWdEFpLnWrTuiH9EibyK3WmfMgHZUIK71lLu2lPEGymDj7Om/JC2trZfKC5mTut4bW R0xv7gc3QedYmmavolL8hjgV3Bf+UEQ2cOOtdU9ePn0QZccZPejOeTT5vQUvagx38Y+n w4uwIxkRq4BHS7J+vwFYPKBG3s0er3o+52QxbUM4YeMJpgAXy2XS/G9UcFTs7tMK8NKf 8uBQ== 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; bh=vW+oVBrKyKiiJASPTJ3TiwNitoa8EthpxoFCyHSWd/o=; b=rUWE6ccsOl3sedL4b/ZsHDMjgDTdF6qKftU6VWtYSFa0Au/K6sWPLQxXlhxLry3dYt a+JidKqL7zMRye9CZ91a1zdjbJgOvpWoajGk42oFMM3fb6QNtWfM6SJbqmShw2krbcQm b0x2Y3OkirVzroPK+unw7QiQVSqO7nKBmhxUNqtwF/x+Ou44g9paxmzUjVw/37orrdon s/DpPRhPqiF1zzimZROMZa6OZAr8QVfV1Ci4XM4tt5qauPex3ETEcJIXVmZnzEIFgljl 7cINWktDxNIfCemZaQ/ItxR3/N4BTLdC5YUPTAFUAOklrrvISIH4Jqzr2EtNwDCbBJRB LMOw== X-Gm-Message-State: ACgBeo2mDN/ZCl9KyNyNmhR8CDIF+3X7kLzf4tQFXgvHP8tvUEeWexfr xt3JJBTij5/FasaQFj2VnZN21QLxQcQ= X-Google-Smtp-Source: AA6agR6UZ60ikAvqjliVx6dur45qqv6QIJlDKUO7GPs9TqCEAJWj+45eJu/GqpbRimoeDhMyCe/mSQ== X-Received: by 2002:a05:6000:1e0f:b0:225:4052:3a68 with SMTP id bj15-20020a0560001e0f00b0022540523a68mr12089375wrb.707.1661342413389; Wed, 24 Aug 2022 05:00:13 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:12 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 01/37] Use DW_ATE_UTF for the Rust 'char' type Date: Wed, 24 Aug 2022 12:59:20 +0100 Message-Id: <20220824115956.737931-2-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Tom Tromey 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. --- gcc/dwarf2out.cc | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc index e3920c898f5..a8bccbabca4 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -5600,6 +5600,16 @@ is_fortran (const_tree decl) return is_fortran (); } +/* Return TRUE if the language is Rust. */ + +static inline bool +is_rust () +{ + unsigned int lang = get_AT_unsigned (comp_unit_die (), DW_AT_language); + + return lang == DW_LANG_Rust || lang == DW_LANG_Rust_old; +} + /* Return TRUE if the language is Ada. */ static inline bool @@ -13231,7 +13241,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; @@ -25201,6 +25215,13 @@ gen_compile_unit_die (const char *filename) } else if (strcmp (language_string, "GNU F77") == 0) language = DW_LANG_Fortran77; + else if (strcmp (language_string, "GNU Rust") == 0) + { + if (dwarf_version >= 5 || !dwarf_strict) + language = DW_LANG_Rust; + else + language = DW_LANG_Rust_old; + } else if (dwarf_version >= 3 || !dwarf_strict) { if (strcmp (language_string, "GNU Ada") == 0) From patchwork Wed Aug 24 11:59:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56978 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 6DA723850212 for ; Wed, 24 Aug 2022 12:01:07 +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 216C2385043C; Wed, 24 Aug 2022 12:00:26 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 216C2385043C Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x433.google.com with SMTP id h5so19676040wru.7; Wed, 24 Aug 2022 05:00:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=IsTU1wqw8+1bgoubFz+cWEDaOKQuY/K1Id53/TusWK8=; b=A1Y4r5OQZyWkF5ixJWtiSFKxZyB6qScycKdNsqrNZjNaWXIRfeS7WnRokR4LrHVjHX CHKEfKd6jUWjebbphotDidQzKbLUWvs86mEXiocHDzSssTXhltnc+RqznpaxV2lC5cMy A+J1Me1B3hS5LOiwJG6QJea3zFtThVNJQpp4ubi0S52XwkR4NMwiLL5EvpUYs5JHen6B uXQ/4NMcUXQBt/cGluOc6MNdHpHSQT72rkQEgqADB14veL4S/tJbjJzKG9bcATARvN5h 10FcNlp5YV0RG/z0jY3VdnqaZ7HhTWQ1k4Lh1ExG/GnzteKxr87FOUU9u1YIGjXxyNwX jcrg== 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; bh=IsTU1wqw8+1bgoubFz+cWEDaOKQuY/K1Id53/TusWK8=; b=10LqdI6SBhTaodNjx8B+nhZmeOjxtK/w8c0THcLE4OGCZMTQwiVLTemmJFGx9QrQAy IaDiLmFQnsx+xq7A+3DjpJkatLGq3tABOo+rtSFWUzIlgyXYymj9imQsd4Vs5BVCXO3B 4N/CtPZ1rPdO4AY4abnGbf2ZMu06CCSRZELxROkG4wnjlF76pxWF+/W/Os4kIXyfZ4Tr 0g+QHWP481lSFaqaygpjOrrPZJ0h4SXAA/fu8a8e2vJx/ag7ArlR+Wfr2VZRTsefYNaj ih42KeBwNsHVy3220ZN9YTA+aeKNjVDtISzdNqvJY6MuqgKtjqDsYvcKAFCVs/JA/Spf OjzQ== X-Gm-Message-State: ACgBeo1KGack/qgKXxe0IhojFfv+q3tiY+5N5iMGtygN22GtRgQOI9zQ 7IiOSc+ooDDAMD5in0XTvVwxaaMJaXc= X-Google-Smtp-Source: AA6agR4aRHZBJ+VGHD0PXpo8W/DPev8dyDpgQgORSQkA1kVbJ+ppi+lnnuuTLQql3aJhDZWK/GyOgw== X-Received: by 2002:a05:6000:250:b0:225:624b:13 with SMTP id m16-20020a056000025000b00225624b0013mr5711899wrz.127.1661342424558; Wed, 24 Aug 2022 05:00:24 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:23 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 02/37] gccrs: Add nessecary hooks for a Rust front-end testsuite Date: Wed, 24 Aug 2022 12:59:21 +0100 Message-Id: <20220824115956.737931-3-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron , Thomas Schwinge , =?utf-8?q?Marc_Poulhi=C3=A8s?= Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron This copy's 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 Wed Aug 24 11:59:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56980 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 C871C384D1A9 for ; Wed, 24 Aug 2022 12:01:41 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x330.google.com (mail-wm1-x330.google.com [IPv6:2a00:1450:4864:20::330]) by sourceware.org (Postfix) with ESMTPS id 7CF6A385023F; Wed, 24 Aug 2022 12:00:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 7CF6A385023F Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wm1-x330.google.com with SMTP id j26so8670933wms.0; Wed, 24 Aug 2022 05:00:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=p4JDD1WbIQhaecFaGqVIjJdoG7TAeLt5iH/ZmRxdkuI=; b=QJ6iqqxlyOcyK1bIntgZo2xuWktOsaorFHi4/9iwAOMAT6YnUh3Sxdo3qz5h+/DJ+r FIpPgfpZRq0+gjGFZ2mR5BlXJ4Sj7//eUXQTthloyCbO9DPOIaUyCbbxXRH/SIycvBKF Wo3tCwtBGViyD0gyn1ZMRbVp0O7vQ6WOA1QK2D2BFaef5tivsnXRFaX5ODxR1cdXH2iD SB4+X9Q0MjMuXJuxchPB2jFrthiFMRs6NSiHeH262I+Nt7VaUftRfglWAdY79n3xL8FQ 4K1Fot7que1SwLJDuDzz03K7fMUxaMPNPD1UHdoVBiQdFNqngSERw6D2UXnZVxy7l4Um VAjw== 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; bh=p4JDD1WbIQhaecFaGqVIjJdoG7TAeLt5iH/ZmRxdkuI=; b=nJBgEQ67mEcKOXRSc2EJrdB+P3VT6j0pDVQaWhSXAGchtWN2FjlPGtvK03knpzwX2T HPtj3uKUTQLfUUCm2uM7JEA9g9C2HbQLVShpxR8Y0I/EndA2buXFuprDg9eqrT9jqoIt h+xxnyw28Jf9oY/EhVQ3Yir3vIoRM+lIDGbgxZ7wI9xAZje9r9aAJzvha6PS/UvsGPxJ tz+3gDctdRGmzggzFgZ5i4vHYf7Nq0fJC3Wb3pvq6E7SWyfaJ59o/9Jo96ISkO1N4+FR PBKrFhu+qCcSKjaIyjGqs9czvlIrOMzDbmCwHolUEESKa9K7bWWyeCbOOeGF3mq9Oxfj zQVQ== X-Gm-Message-State: ACgBeo3VhJXqJ1xcSuSkj3tHzgq1pQ7B3XZMfZzvuK+z8EptsLWsLr2C 3lmqjGst/iKDcD5f2klBjmfC6TyIs04= X-Google-Smtp-Source: AA6agR7lW9hgwQYAws18zx4Q4jCszY0CFcGQNzL26zZDVg5Ak2lx4pG649S71odQRqACmKPup/bn0w== X-Received: by 2002:a1c:7916:0:b0:3a6:3540:5b3c with SMTP id l22-20020a1c7916000000b003a635405b3cmr4923175wme.178.1661342428057; Wed, 24 Aug 2022 05:00:28 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:27 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 03/37] gccrs: Add Debug info testsuite Date: Wed, 24 Aug 2022 12:59:22 +0100 Message-Id: <20220824115956.737931-4-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron , Tom Tromey 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 --- 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..ddacf0e4392 --- /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" } +// DW_LANG_Rust_old is 0x9000 +// { dg-final { scan-assembler "0x9000\[ \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 Wed Aug 24 11:59:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56983 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 2CD5C384B121 for ; Wed, 24 Aug 2022 12:02:24 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x436.google.com (mail-wr1-x436.google.com [IPv6:2a00:1450:4864:20::436]) by sourceware.org (Postfix) with ESMTPS id C6CE6384D19E; Wed, 24 Aug 2022 12:00:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C6CE6384D19E Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x436.google.com with SMTP id z16so1688794wrh.10; Wed, 24 Aug 2022 05:00:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=UoinBedO3DC9KUT7KTx0GF4jy1PPEGkTBIUBYtOTP1w=; b=HEEQoyZ2+MlT6nyEAZ2gJoJG/abRNniY9U9LZQfOh97CMFhd2zm4UxEwHkztgjHNmf MQLs9PbSDF4UukUFvVKQa8JLVac+HhBbLDnE9YHNhbvSrrNw3yckKesUim+VruslH4sq SZm+pXCh9tNUljGa3R7KzkBfeCdPBCZ6TM8JfiG17/27BZy8O5lS81Ik3wMoz1u4KAdL u3wCe74JTnOhfpbWUA0s2MCE9oDQQzGV0O82xEAJs3EeK2Bov9qG5wDcBhJ0TvU1Diu4 SvrzsGTyUhXDl6eX1YsyOGlfnp4ep8Kx4AOK8V+cBf4kA0xqyOC+YuppdoO2gNAFQ7Qc t+iQ== 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; bh=UoinBedO3DC9KUT7KTx0GF4jy1PPEGkTBIUBYtOTP1w=; b=IPid/BEFvTEejENrgVIxQZWcpnN5fvI8J65ZmggVH4Gl+cN2Yxg4vGZPoCayMhdJbE HbvdhnG7eX95yHlI3MjrZ21Umdgi0CvLZt0BXw6+m2d8XSta9g4FMTCJjMIcFU3+dJax lYfvNlpbVauOKUCoULaNjcvczlAP5du1pZLZRCQfrxh9gSMZ9bphASbEnAV0gUcgO7WE eBn6NtABzaTnA6h3ixskzSv+BtCQ+WCfrAbz6vGUslCsERQ0NpwWmeGjFRmKIdD9Bhve hSteN830JJ17s6T7LR5lrGS1whoALKjvIN2z6aGrdHjKQKDVYEoci5hmkiLtH+tDZUbA gcow== X-Gm-Message-State: ACgBeo0EkvQs2DtAUijTfZCPG9XjYhDQa3uoDba2zKA+9KN+7ER1RmRm 42XEVXntpUFCNRRHetD7ysQuAoOZl/Q= X-Google-Smtp-Source: AA6agR7wx/BPHDsbWDOM/fQmSANCJBthsWgrb+VGeZzZI3k/rVQhGKdgpWebzRwG7VFRQFSKbKvRKA== X-Received: by 2002:a5d:67c6:0:b0:225:2a3e:6384 with SMTP id n6-20020a5d67c6000000b002252a3e6384mr15660204wrw.23.1661342429988; Wed, 24 Aug 2022 05:00:29 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:29 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 04/37] gccrs: Add link cases testsuite Date: Wed, 24 Aug 2022 12:59:23 +0100 Message-Id: <20220824115956.737931-5-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron 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 which uses a pattern that 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 leaving 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 Wed Aug 24 11:59:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56987 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 C09CC384D1BD for ; Wed, 24 Aug 2022 12:03:24 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com [IPv6:2a00:1450:4864:20::329]) by sourceware.org (Postfix) with ESMTPS id 11997384D169; Wed, 24 Aug 2022 12:00:35 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 11997384D169 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wm1-x329.google.com with SMTP id ay12so8656480wmb.1; Wed, 24 Aug 2022 05:00:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=4Zx2naMINAeeouJbrJFTlh3rrVAcytOwARVkhQ59FGI=; b=BEpBtm68rbR90pfDAh+M47R+0niFv/ZdhqbGnyCx4ti1Fv+TV+dZObTykhGy9NjXN4 1gP55mOmEKBL8Jw+/LjlM9jsdxnI9+dK/iRrhxtUcDpQEE4xfTubjuzA4JPVxVvyNrfZ jK+B3bxFfGU+pUQAGIoJpdGuUpVEJQheUJPGdUq3xRCxjan4GAlFgvI6PWqxkGahA5bY sCxR+IyuXva9xOnpd0a0Eg1F3F+wjH7gMbfLT8N2ZcWx5FixBdDUxVhWorbJl3wChT3g XQdMeMeVcrOs6eW/OV2dkke5dNwOXnVkKxCS8UoK1SqLjnzp30HbX2le8EOwdOm03h31 W8Hw== 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; bh=4Zx2naMINAeeouJbrJFTlh3rrVAcytOwARVkhQ59FGI=; b=JXevuLLYFtlMHPDMzmV5X1fznF/mMguabPqXAqNH+KJE3saLyipOIfHf1P6j0h3d/7 dZ79H4Q1CbwzOvPE6UnSpUXYNWlnLTNDzQn0LE1D9PVDejIMB856R7+HfhNdKj5+eWj6 4IVMu3bT289iCMcvwHnZzagf94DZqYpcmwxPbaOc1JExKQXRe1HzIzn2ujwRh+saAysy uOxVDC/w7J4qpIJATfAgRWzpZIwdR3lkYRNWJPvNPZQcK5vmoW8L7ZcesWCpDnNjy1QE lM2/ekSk6Yi58oJROyzR0erToFxLCO7QBD0JefwUlvBPErIcHnUSae3rzSct4dv40heq WuYw== X-Gm-Message-State: ACgBeo2TLSIXkarHVxAR9HsBh/lqSLe3F6WWLkf7SeuBc7vXHwbV+alf ta39vue27jBp2qwM6ChovqWPLCiTsrQ= X-Google-Smtp-Source: AA6agR6JDCkBIx3SWjnCslTbfC/uDwUm9ISmd1V2iOIF5LX00mzEPkUp7XrAN4SFA1w5o99uTuaSCw== X-Received: by 2002:a05:600c:6025:b0:3a6:ff6:de7e with SMTP id az37-20020a05600c602500b003a60ff6de7emr5034784wmb.173.1661342431790; Wed, 24 Aug 2022 05:00:31 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:31 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 05/37] gccrs: Add general compilation test cases Date: Wed, 24 Aug 2022 12:59:24 +0100 Message-Id: <20220824115956.737931-6-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-5.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: =?utf-8?q?Marc_Poulhi=C3=A8s?= , Philip Herron , Mark Wielaard , Arthur Cohen , gcc-rust@gcc.gnu.org, Thomas Schwinge 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 are all dg-compile tests which contain dg-warning or dg-error annotations and some with no annotations to ensure they do create a resulting asm output. The second section is the same but have tests which are ran with the full torture options, as during development the test case may have had 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 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 new file mode 100644 index 00000000000..ae51e36c87f --- /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 Wed Aug 24 11:59:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56982 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 DF611394D8EC for ; Wed, 24 Aug 2022 12:01:55 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x429.google.com (mail-wr1-x429.google.com [IPv6:2a00:1450:4864:20::429]) by sourceware.org (Postfix) with ESMTPS id E1EEF384F027; Wed, 24 Aug 2022 12:00:37 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org E1EEF384F027 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x429.google.com with SMTP id bs25so20503508wrb.2; Wed, 24 Aug 2022 05:00:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=ToySAx65SIKAJDX8LQ2D5Y+sKCaHzlfNDg4SctYvC5k=; b=CXbQUZTB0Irw7HqofvirUJJepvRUK/+KUekst7Gqn90XrulVV+eIamiroNqz3Hnj2J SR8uQQFM4HA0ePmu32v+Dan7wVbqntnjb/qlElfYNB1aCNDPqwx7QpIYor8lXlZjaaWd UNywJoyHZT0yhaxy2cs7uOJh4+bAYGccpETkeVgbPgNSYR3tcBkbwK9oIrDnn5VzhtuA yBhf47B12wQTmrMC7nouc73j8BkuWVTKFHEtnc1k2iY/tGdrzySAbG17SnrneSnvLj3C w8+IUhDPIP2A4WHgJpagelfdpGNYFpPeABLqR6rY1riU3fL3bWrA4XnEGSjtp/fs9jhN pQVg== 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; bh=ToySAx65SIKAJDX8LQ2D5Y+sKCaHzlfNDg4SctYvC5k=; b=k+T6ifij51bCcKnVENY6dct08Mz/g51lgJx+VlG8YpuE9aW/3ZMk6DE5VRgODMKtmp +oam/qx3zkcHWEQ5w2Dg+Wi0dxiQ+4sXmRhgnl+yzMd+qL80yc4Ud8vdtK8cc2AN1P+c ODiI2/KltkXgGvyzKahuMu99/vTGJZjKtBGdhNcaB6AluzHCFu8+Z8wrJ4Vxb7l02GsY M5K1gDB8aui6uxiRtwk/wGAava6ponOfyEElZJuklc4OAjnbzqhZkXTkoFyuNrOTOReU /V5TeC15fwDM4qThh5sXAsh5Q0V2kW4uX5ZMBFGfhCRU4BMevI7A5aJvu2OTO0kVrXNN WZcw== X-Gm-Message-State: ACgBeo0N6Ra4fkXO6cQ/62ra3q97OD8Xq+KHhcZGipPdR1nHZFPkyBz+ SaGQyAV5A1ImT/fjaB0BzAk68V9dHqM= X-Google-Smtp-Source: AA6agR47rHWn1kt8WmWZhXpCgU5uCJgKSBRkQ1xzlRSaTIy56/jAsRLhpgoqyzG79oiFBv1NaTyCvA== X-Received: by 2002:a5d:6a50:0:b0:225:5dd6:873f with SMTP id t16-20020a5d6a50000000b002255dd6873fmr6497346wrw.101.1661342433777; Wed, 24 Aug 2022 05:00:33 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:33 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 06/37] gccrs: Add execution test cases Date: Wed, 24 Aug 2022 12:59:25 +0100 Message-Id: <20220824115956.737931-7-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: =?utf-8?q?Marc_Poulhi=C3=A8s?= , Philip Herron , Mark Wielaard , Arthur Cohen , gcc-rust@gcc.gnu.org, Thomas Schwinge 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 so they get compiled, linked and executed by default, all the while being compiled with the matrix of torture options. The only caveat here is that currently gccrs does not currently support the main shim yet so we have a C-style main function here returning zero which is not supported in Rustc. 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 Wed Aug 24 11:59:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56985 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 A3583395380B for ; Wed, 24 Aug 2022 12:02:56 +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 4552E384D15A; Wed, 24 Aug 2022 12:00:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 4552E384D15A Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wm1-x332.google.com with SMTP id m17-20020a7bce11000000b003a5bedec07bso801497wmc.0; Wed, 24 Aug 2022 05:00:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=8T8GbiKhgPYZRZV5H23CKHO8b5/0wiJQ2GCgfG67Ky8=; b=QLC2UNlzph6Km+OgDBuwIq2ecgQeX8Ybc7pPwDUorIkhTMSKqH7g2mnZXpKPoxlIYb XmLObD0984ywRfRUqN2CrJYzdP4r0datzSejob+m+/gOgqecdTRtZaMfsZ4Xde26VKX6 6MY3Qe1zHyBBX53CCrmthv9AU9LxD21ctpgVOb3X5muH08SkLbZcY4d1MQKjjk77CaaV 4RZb7Wp8u9nmdvZkRMR287Ms4jZTI5eJ6NCNNEbKG9/4/L1DrjXn9QwZd7wonnFUCtGa DfQVLmI1aI2IGV8fCH3X6Q5nbqdS4JVItQXaajrFMva8vwvfGGzRAaEWs55xmaMy+9cg M8ig== 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; bh=8T8GbiKhgPYZRZV5H23CKHO8b5/0wiJQ2GCgfG67Ky8=; b=kLK6wgs+V/U2NE8E/955sKxnUaiDYf+C2rV7zmmw9KNuGB9eEfNO4vCtsFqlN1pwY+ S6yZa+mjT/4QnXENnL233ajGPWxvl652YAMPt7GW8RhQGzMVeSHbYoIrjAi8Fs1Myb8h HpvxomCFXw6FaRKkrAhmh1NjG5iZjK26mbwiyVuhxu49DP8xnAkFLoNl2W5coZ2rSxg3 Lx0e0hAwIPcbBj3A/9uTSZY7Rle6Bxkj7N0TEWmpxDVeZFTyESe95si9uxVeZPdsx8pu X2VOvw7FdZ0LnoGavT5ptugqjwFdFJazkswxQDKZY72WZUHp5GPnk5Abka23rN7MjwDd ZEqA== X-Gm-Message-State: ACgBeo1X8aY9ykKMLoCUAcBoy+f7oVTU31Dhd14zol9DKhtG8rm+c+PT a6jL919TvM5L3LTNljjXfWSVGrp0toY= X-Google-Smtp-Source: AA6agR7sawz94aKbN/dUjgWQC2ZLUqmZfnE4bxcmdrboUygSRejCEUojIP/q1m9InpfV1uldeM0Jig== X-Received: by 2002:a05:600c:501f:b0:3a5:54ff:625f with SMTP id n31-20020a05600c501f00b003a554ff625fmr5191967wmr.5.1661342434830; Wed, 24 Aug 2022 05:00:34 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:34 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 07/37] gccrs: Add gcc-check-target check-rust Date: Wed, 24 Aug 2022 12:59:26 +0100 Message-Id: <20220824115956.737931-8-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron 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 autogen target * 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 Wed Aug 24 11:59:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56979 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 6CC2C384C001 for ; Wed, 24 Aug 2022 12:01:27 +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 69C6F3851160; Wed, 24 Aug 2022 12:00:42 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 69C6F3851160 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x434.google.com with SMTP id k9so20508511wri.0; Wed, 24 Aug 2022 05:00:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=45iNqmyUxhCeI7HmM8WLC1wQEUfiNNjC7AKM0nRHaTY=; b=YxU1J2OtU6M94thhg9Bye/iTIfVFjAeXmt08fAtSx3P0de3VanHDBT3s4F2aC1U1j6 6CNxllXgsQWpJ66HpKqXKBROAkPjTDoUe5G09q1/OzrQ5iXZigQEz31IMLUIWwqRzeO/ CjwBGQCmTNuQ39ekchhhxjqmdGODqRgXWEF2E+2PdrI1aOoUx30HMD5h32X9dB0muQM4 7BS2OItKRZsbFq3YxWZqNlM86bhxos/K8j+64oN768vFblAduKDJvzAYrVcDNggtjR1G 06btLWbBjKhA6GfTFvBhjaBG9F6afJqyHyKSwcICwxo2/5T+8FZjFkFAYKGe2pa2My8p xYng== 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; bh=45iNqmyUxhCeI7HmM8WLC1wQEUfiNNjC7AKM0nRHaTY=; b=eGqFeQQE0HBfAfjFWOIsg+7gT6Gp9NYlECms8oW75yZYiip8dp1TMmHHhLYnl1yXkw HxBqOFfZcz0b9AP9QO5xv4zGe/7c2vdR8RoKepSZmA1ZYV1qqTk0Ygk9d2eKHKS82ZLN MZHlHA6NW0pljONQrZDl8LcyZ/TAIb/QL9AyR6oiV0WFAXWZfdtzlibUUvBNMu+sdHzn e4tbErPo+ASa2Ercu2LYB5bFTLJIzUgvS2pXM9TgBWVksc3bixESo9JZXBK4xpxCBkbT Pw8VAxT3VE4emFc6wrbLyGo3eiohbI6rOxWlHBzIw9ua1nKoknzjjsrTvo/tpx13sKVD yZ0g== X-Gm-Message-State: ACgBeo2PqZul4br6WKAy70eIICyoERMGVtZf8NsF5XXcvH8RY7gNyRRq T4T/5ihnzyKOCUVr03Qs48d/4tNN7/8= X-Google-Smtp-Source: AA6agR7Uh6G+ughX0ukPHIWANqDYyQ9sYwxO3rD4tSiOy8kuBBGwDsTCidJy8bXo/5g9oeFDAkjm2Q== X-Received: by 2002:a05:6000:12c3:b0:225:3063:82a6 with SMTP id l3-20020a05600012c300b00225306382a6mr14813095wrx.541.1661342438967; Wed, 24 Aug 2022 05:00:38 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:38 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 09/37] gccrs: Add Lexer for Rust front-end Date: Wed, 24 Aug 2022 12:59:28 +0100 Message-Id: <20220824115956.737931-10-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: The Other , Arthur Cohen , Mark Wielaard , gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: The Other The lexer is refered to as a ManagedTokenSource within the parser, this lexer does not currently support unicode but serves as a starting point to do so. Co-authored-by: Philip Herron Co-authored-by: Arthur Cohen Co-authored-by: Mark Wielaard --- gcc/rust/lex/rust-codepoint.h | 46 + gcc/rust/lex/rust-lex.cc | 2729 ++++++++++++++++++++++++++++++++ gcc/rust/lex/rust-lex.h | 271 ++++ gcc/rust/lex/rust-token.cc | 135 ++ gcc/rust/lex/rust-token.h | 455 ++++++ gcc/rust/rust-buffered-queue.h | 204 +++ 6 files changed, 3840 insertions(+) create mode 100644 gcc/rust/lex/rust-codepoint.h create mode 100644 gcc/rust/lex/rust-lex.cc create mode 100644 gcc/rust/lex/rust-lex.h create mode 100644 gcc/rust/lex/rust-token.cc create mode 100644 gcc/rust/lex/rust-token.h create mode 100644 gcc/rust/rust-buffered-queue.h diff --git a/gcc/rust/lex/rust-codepoint.h b/gcc/rust/lex/rust-codepoint.h new file mode 100644 index 00000000000..22da080bbb2 --- /dev/null +++ b/gcc/rust/lex/rust-codepoint.h @@ -0,0 +1,46 @@ +// 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_CODEPOINT_H +#define RUST_CODEPOINT_H + +#include + +namespace Rust { +struct Codepoint +{ + uint32_t value; + + // Creates a zero codepoint. + Codepoint () : value (0) {} + + // Creates a codepoint from an encoded UTF-8 value. + Codepoint (uint32_t value) : value (value) {} + + static Codepoint eof () { return Codepoint (UINT32_MAX); } + bool is_eof () const { return value == UINT32_MAX; } + + // Returns a C++ string containing string value of codepoint. + std::string as_string (); + + bool operator== (Codepoint other) const { return value == other.value; } + bool operator!= (Codepoint other) const { return !operator== (other); } +}; +} // namespace Rust + +#endif diff --git a/gcc/rust/lex/rust-lex.cc b/gcc/rust/lex/rust-lex.cc new file mode 100644 index 00000000000..70e6b50209f --- /dev/null +++ b/gcc/rust/lex/rust-lex.cc @@ -0,0 +1,2729 @@ +// 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 +// . + +#include "rust-lex.h" + +#include "rust-system.h" // for rust_assert and rust_unreachable +#include "rust-diagnostics.h" // for rust_error_at +#include "rust-linemap.h" +#include "rust-session-manager.h" +#include "safe-ctype.h" + +namespace Rust { +// TODO: move to separate compilation unit? +// overload += for uint32_t to allow 32-bit encoded utf-8 to be added +std::string & +operator+= (std::string &str, Codepoint char32) +{ + if (char32.value < 0x80) + { + str += static_cast (char32.value); + } + else if (char32.value < (0x1F + 1) << (1 * 6)) + { + str += static_cast (0xC0 | ((char32.value >> 6) & 0x1F)); + str += static_cast (0x80 | ((char32.value >> 0) & 0x3F)); + } + else if (char32.value < (0x0F + 1) << (2 * 6)) + { + str += static_cast (0xE0 | ((char32.value >> 12) & 0x0F)); + str += static_cast (0x80 | ((char32.value >> 6) & 0x3F)); + str += static_cast (0x80 | ((char32.value >> 0) & 0x3F)); + } + else if (char32.value < (0x07 + 1) << (3 * 6)) + { + str += static_cast (0xF0 | ((char32.value >> 18) & 0x07)); + str += static_cast (0x80 | ((char32.value >> 12) & 0x3F)); + str += static_cast (0x80 | ((char32.value >> 6) & 0x3F)); + str += static_cast (0x80 | ((char32.value >> 0) & 0x3F)); + } + else + { + rust_debug ("Invalid unicode codepoint found: '%u' ", char32.value); + } + return str; +} + +std::string +Codepoint::as_string () +{ + std::string str; + + // str += Codepoint (value); + str += *this; + + return str; +} + +/* Includes all allowable float digits EXCEPT _ and . as that needs lookahead + * for handling. */ +bool +is_float_digit (char number) +{ + return ISDIGIT (number) || number == 'E' || number == 'e'; +} + +/* Basically ISXDIGIT from safe-ctype but may change if Rust's encoding or + * whatever is different */ +bool +is_x_digit (char number) +{ + return ISXDIGIT (number); +} + +bool +is_octal_digit (char number) +{ + return number >= '0' && number <= '7'; +} + +bool +is_bin_digit (char number) +{ + return number == '0' || number == '1'; +} + +bool +check_valid_float_dot_end (char character) +{ + return character != '.' && character != '_' && !ISALPHA (character); +} + +// ISSPACE from safe-ctype but may change in future +bool +is_whitespace (char character) +{ + return ISSPACE (character); +} + +bool +is_non_decimal_int_literal_separator (char character) +{ + return character == 'x' || character == 'o' || character == 'b'; +} + +Lexer::Lexer (const std::string &input) + : input (RAIIFile::create_error ()), current_line (1), current_column (1), + line_map (nullptr), raw_input_source (new BufferInputSource (input, 0)), + input_queue{*raw_input_source}, token_queue (TokenSource (this)) +{} + +Lexer::Lexer (const char *filename, RAIIFile file_input, Linemap *linemap) + : input (std::move (file_input)), current_line (1), current_column (1), + line_map (linemap), + raw_input_source (new FileInputSource (input.get_raw ())), + input_queue{*raw_input_source}, token_queue (TokenSource (this)) +{ + // inform line_table that file is being entered and is in line 1 + if (linemap) + line_map->start_file (filename, current_line); +} + +Lexer::~Lexer () +{ + /* ok apparently stop (which is equivalent of original code in destructor) is + * meant to be called after all files have finished parsing, for cleanup. On + * the other hand, actual code that it calls to leave a certain line map is + * mentioned in GCC docs as being useful for "just leaving an included header" + * and stuff like that, so this line mapping functionality may need fixing. + * FIXME: find out whether this occurs. */ + + // line_map->stop(); +} + +/* TODO: need to optimise somehow to avoid the virtual function call in the + * tight loop. Best idea at the moment is CRTP, but that might make lexer + * implementation annoying when storing the "base class" (i.e. would need + * template parameter everywhere), although in practice it would mostly just + * look ugly and make enclosing classes like Parser also require a type + * parameter. At this point a macro might be better. OK I guess macros can be + * replaced by constexpr if or something if possible. */ +Location +Lexer::get_current_location () +{ + if (line_map) + return line_map->get_location (current_column); + else + // If we have no linemap, we're lexing something without proper locations + return Location (); +} + +int +Lexer::peek_input (int n) +{ + return input_queue.peek (n); +} + +int +Lexer::peek_input () +{ + return peek_input (0); +} + +void +Lexer::skip_input (int n) +{ + input_queue.skip (n); +} + +void +Lexer::skip_input () +{ + skip_input (0); +} + +void +Lexer::replace_current_token (TokenPtr replacement) +{ + token_queue.replace_current_value (replacement); + + rust_debug ("called 'replace_current_token' - this is deprecated"); +} + +/* shitty anonymous namespace that can only be accessed inside the compilation + * unit - used for classify_keyword binary search in sorted array of keywords + * created with x-macros. */ +namespace { +// TODO: make constexpr when update to c++20 +const std::string keyword_index[] = { +#define RS_TOKEN(x, y) +#define RS_TOKEN_KEYWORD(name, keyword) keyword, + RS_TOKEN_LIST +#undef RS_TOKEN_KEYWORD +#undef RS_TOKEN +}; + +constexpr TokenId keyword_keys[] = { +#define RS_TOKEN(x, y) +#define RS_TOKEN_KEYWORD(name, keyword) name, + RS_TOKEN_LIST +#undef RS_TOKEN_KEYWORD +#undef RS_TOKEN +}; + +constexpr int num_keywords = sizeof (keyword_index) / sizeof (*keyword_index); +} // namespace + +/* Determines whether the string passed in is a keyword or not. If it is, it + * returns the keyword name. */ +TokenId +Lexer::classify_keyword (const std::string &str) +{ + const std::string *last = keyword_index + num_keywords; + const std::string *idx = std::lower_bound (keyword_index, last, str); + + if (idx == last || str != *idx) + return IDENTIFIER; + + // TODO: possibly replace this x-macro system with something like hash map? + + // We now have the expected token ID of the reserved keyword. However, some + // keywords are reserved starting in certain editions. For example, `try` is + // only a reserved keyword in editions >=2018. The language might gain new + // reserved keywords in the future. + // + // https://doc.rust-lang.org/reference/keywords.html#reserved-keywords + auto id = keyword_keys[idx - keyword_index]; + + // `try` is not a reserved keyword before 2018 + if (Session::get_instance ().options.get_edition () + == CompileOptions::Edition::E2015 + && id == TRY) + return IDENTIFIER; + + return id; +} + +TokenPtr +Lexer::build_token () +{ + // loop to go through multiple characters to build a single token + while (true) + { + Location loc = get_current_location (); + current_char = peek_input (); + skip_input (); + + // detect UTF8 bom + // + // Must be the first thing on the first line. + // There might be an optional BOM (Byte Order Mark), which for UTF-8 is + // the three bytes 0xEF, 0xBB and 0xBF. These can simply be skipped. + if (current_line == 1 && current_column == 1 && current_char == 0xef + && peek_input () == 0xbb && peek_input (1) == 0xbf) + { + skip_input (1); + current_char = peek_input (); + skip_input (); + } + + // detect shebang + // Must be the first thing on the first line, starting with #! + // But since an attribute can also start with an #! we don't count it as a + // shebang line when after any whitespace or comments there is a [. If it + // is a shebang line we simple drop the line. Otherwise we don't consume + // any characters and fall through to the real tokenizer. + if (current_line == 1 && current_column == 1 && current_char == '#' + && peek_input () == '!') + { + int n = 1; + while (true) + { + int next_char = peek_input (n); + if (is_whitespace (next_char)) + n++; + else if ((next_char == '/' && peek_input (n + 1) == '/' + && peek_input (n + 2) != '!' + && peek_input (n + 2) != '/') + || (next_char == '/' && peek_input (n + 1) == '/' + && peek_input (n + 2) == '/' + && peek_input (n + 3) == '/')) + { + // two // or four //// + // A single line comment + // (but not an inner or outer doc comment) + n += 2; + next_char = peek_input (n); + while (next_char != '\n' && next_char != EOF) + { + n++; + next_char = peek_input (n); + } + if (next_char == '\n') + n++; + } + else if (next_char == '/' && peek_input (n + 1) == '*' + && peek_input (n + 2) == '*' + && peek_input (n + 3) == '/') + { + /**/ + n += 4; + } + else if (next_char == '/' && peek_input (n + 1) == '*' + && peek_input (n + 2) == '*' && peek_input (n + 3) == '*' + && peek_input (n + 4) == '/') + { + /***/ + n += 5; + } + else if ((next_char == '/' && peek_input (n + 1) == '*' + && peek_input (n + 2) != '*' + && peek_input (n + 2) != '!') + || (next_char == '/' && peek_input (n + 1) == '*' + && peek_input (n + 2) == '*' + && peek_input (n + 3) == '*')) + { + // one /* or three /*** + // Start of a block comment + // (but not an inner or outer doc comment) + n += 2; + int level = 1; + while (level > 0) + { + if (peek_input (n) == EOF) + break; + else if (peek_input (n) == '/' + && peek_input (n + 1) == '*') + { + n += 2; + level += 1; + } + else if (peek_input (n) == '*' + && peek_input (n + 1) == '/') + { + n += 2; + level -= 1; + } + else + n++; + } + } + else if (next_char != '[') + { + // definitely shebang, ignore the first line + while (current_char != '\n' && current_char != EOF) + { + current_char = peek_input (); + skip_input (); + } + + // newline + current_line++; + current_column = 1; + // tell line_table that new line starts + start_line (current_line, max_column_hint); + break; + } + else + break; /* Definitely not a shebang line. */ + } + } + + // return end of file token if end of file + if (current_char == EOF) + return Token::make (END_OF_FILE, loc); + + // if not end of file, start tokenising + switch (current_char) + { + /* ignore whitespace characters for tokens but continue updating + * location */ + case '\n': // newline + current_line++; + current_column = 1; + // tell line_table that new line starts + start_line (current_line, max_column_hint); + continue; + case '\r': // cr + // Ignore, we expect a newline (lf) soon. + continue; + case ' ': // space + current_column++; + continue; + case '\t': // tab + // width of a tab is not well-defined, assume 8 spaces + current_column += 8; + continue; + + // punctuation - actual tokens + case '=': + if (peek_input () == '>') + { + // match arm arrow + skip_input (); + current_column += 2; + + return Token::make (MATCH_ARROW, loc); + } + else if (peek_input () == '=') + { + // equality operator + skip_input (); + current_column += 2; + + return Token::make (EQUAL_EQUAL, loc); + } + else + { + // assignment operator + current_column++; + return Token::make (EQUAL, loc); + } + case '(': + current_column++; + return Token::make (LEFT_PAREN, loc); + case '-': + if (peek_input () == '>') + { + // return type specifier + skip_input (); + current_column += 2; + + return Token::make (RETURN_TYPE, loc); + } + else if (peek_input () == '=') + { + // minus-assign + skip_input (); + current_column += 2; + + return Token::make (MINUS_EQ, loc); + } + else + { + // minus + current_column++; + return Token::make (MINUS, loc); + } + case '+': + if (peek_input () == '=') + { + // add-assign + skip_input (); + current_column += 2; + + return Token::make (PLUS_EQ, loc); + } + else + { + // add + current_column++; + return Token::make (PLUS, loc); + } + case ')': + current_column++; + return Token::make (RIGHT_PAREN, loc); + case ';': + current_column++; + return Token::make (SEMICOLON, loc); + case '*': + if (peek_input () == '=') + { + // multiplication-assign + skip_input (); + current_column += 2; + + return Token::make (ASTERISK_EQ, loc); + } + else + { + // multiplication + current_column++; + return Token::make (ASTERISK, loc); + } + case ',': + current_column++; + return Token::make (COMMA, loc); + case '/': + if (peek_input () == '=') + { + // division-assign + skip_input (); + current_column += 2; + + return Token::make (DIV_EQ, loc); + } + else if ((peek_input () == '/' && peek_input (1) != '!' + && peek_input (1) != '/') + || (peek_input () == '/' && peek_input (1) == '/' + && peek_input (2) == '/')) + { + // two // or four //// + // single line comment + // (but not an inner or outer doc comment) + skip_input (); + current_column += 2; + current_char = peek_input (); + + // basically ignore until line finishes + while (current_char != '\n' && current_char != EOF) + { + skip_input (); + current_column++; // not used + current_char = peek_input (); + } + continue; + } + else if (peek_input () == '/' + && (peek_input (1) == '!' || peek_input (1) == '/')) + { + /* single line doc comment, inner or outer. */ + bool is_inner = peek_input (1) == '!'; + skip_input (1); + current_column += 3; + + std::string str; + str.reserve (32); + current_char = peek_input (); + while (current_char != '\n') + { + skip_input (); + if (current_char == '\r') + { + char next_char = peek_input (); + if (next_char == '\n') + { + current_char = '\n'; + break; + } + rust_error_at ( + loc, "Isolated CR %<\\r%> not allowed in doc comment"); + current_char = next_char; + continue; + } + if (current_char == EOF) + { + rust_error_at ( + loc, "unexpected EOF while looking for end of comment"); + break; + } + str += current_char; + current_char = peek_input (); + } + skip_input (); + current_line++; + current_column = 1; + // tell line_table that new line starts + start_line (current_line, max_column_hint); + + str.shrink_to_fit (); + if (is_inner) + return Token::make_inner_doc_comment (loc, std::move (str)); + else + return Token::make_outer_doc_comment (loc, std::move (str)); + } + else if (peek_input () == '*' && peek_input (1) == '*' + && peek_input (2) == '/') + { + /**/ + skip_input (2); + current_column += 4; + continue; + } + else if (peek_input () == '*' && peek_input (1) == '*' + && peek_input (2) == '*' && peek_input (3) == '/') + { + /***/ + skip_input (3); + current_column += 5; + continue; + } + else if ((peek_input () == '*' && peek_input (1) != '!' + && peek_input (1) != '*') + || (peek_input () == '*' && peek_input (1) == '*' + && peek_input (2) == '*')) + { + // one /* or three /*** + // block comment + // (but not an inner or outer doc comment) + skip_input (); + current_column += 2; + + int level = 1; + while (level > 0) + { + current_char = peek_input (); + + if (current_char == EOF) + { + rust_error_at ( + loc, "unexpected EOF while looking for end of comment"); + break; + } + + // if /* found + if (current_char == '/' && peek_input (1) == '*') + { + // skip /* characters + skip_input (1); + + current_column += 2; + + level += 1; + continue; + } + + // ignore until */ is found + if (current_char == '*' && peek_input (1) == '/') + { + // skip */ characters + skip_input (1); + + current_column += 2; + + level -= 1; + continue; + } + + if (current_char == '\n') + { + skip_input (); + current_line++; + current_column = 1; + // tell line_table that new line starts + start_line (current_line, max_column_hint); + continue; + } + + skip_input (); + current_column++; + } + + // refresh new token + continue; + } + else if (peek_input () == '*' + && (peek_input (1) == '!' || peek_input (1) == '*')) + { + // block doc comment, inner /*! or outer /** + bool is_inner = peek_input (1) == '!'; + skip_input (1); + current_column += 3; + + std::string str; + str.reserve (96); + + int level = 1; + while (level > 0) + { + current_char = peek_input (); + + if (current_char == EOF) + { + rust_error_at ( + loc, "unexpected EOF while looking for end of comment"); + break; + } + + // if /* found + if (current_char == '/' && peek_input (1) == '*') + { + // skip /* characters + skip_input (1); + current_column += 2; + + level += 1; + str += "/*"; + continue; + } + + // ignore until */ is found + if (current_char == '*' && peek_input (1) == '/') + { + // skip */ characters + skip_input (1); + current_column += 2; + + level -= 1; + if (level > 0) + str += "*/"; + continue; + } + + if (current_char == '\r' && peek_input (1) != '\n') + rust_error_at ( + loc, "Isolated CR %<\\r%> not allowed in doc comment"); + + if (current_char == '\n') + { + skip_input (); + current_line++; + current_column = 1; + // tell line_table that new line starts + start_line (current_line, max_column_hint); + str += '\n'; + continue; + } + + str += current_char; + skip_input (); + current_column++; + } + + str.shrink_to_fit (); + if (is_inner) + return Token::make_inner_doc_comment (loc, std::move (str)); + else + return Token::make_outer_doc_comment (loc, std::move (str)); + } + else + { + // division + current_column++; + return Token::make (DIV, loc); + } + case '%': + if (peek_input () == '=') + { + // modulo-assign + skip_input (); + current_column += 2; + + return Token::make (PERCENT_EQ, loc); + } + else + { + // modulo + current_column++; + return Token::make (PERCENT, loc); + } + case '^': + if (peek_input () == '=') + { + // xor-assign? + skip_input (); + current_column += 2; + + return Token::make (CARET_EQ, loc); + } + else + { + // xor? + current_column++; + return Token::make (CARET, loc); + } + case '<': + if (peek_input () == '<') + { + if (peek_input (1) == '=') + { + // left-shift assign + skip_input (1); + current_column += 3; + + return Token::make (LEFT_SHIFT_EQ, loc); + } + else + { + // left-shift + skip_input (); + current_column += 2; + + return Token::make (LEFT_SHIFT, loc); + } + } + else if (peek_input () == '=') + { + // smaller than or equal to + skip_input (); + current_column += 2; + + return Token::make (LESS_OR_EQUAL, loc); + } + else + { + // smaller than + current_column++; + return Token::make (LEFT_ANGLE, loc); + } + break; + case '>': + if (peek_input () == '>') + { + if (peek_input (1) == '=') + { + // right-shift-assign + skip_input (1); + current_column += 3; + + return Token::make (RIGHT_SHIFT_EQ, loc); + } + else + { + // right-shift + skip_input (); + current_column += 2; + + return Token::make (RIGHT_SHIFT, loc); + } + } + else if (peek_input () == '=') + { + // larger than or equal to + skip_input (); + current_column += 2; + + return Token::make (GREATER_OR_EQUAL, loc); + } + else + { + // larger than + current_column++; + return Token::make (RIGHT_ANGLE, loc); + } + case ':': + if (peek_input () == ':') + { + // scope resolution :: + skip_input (); + current_column += 2; + + return Token::make (SCOPE_RESOLUTION, loc); + } + else + { + // single colon : + current_column++; + return Token::make (COLON, loc); + } + case '!': + // no special handling for macros in lexer? + if (peek_input () == '=') + { + // not equal boolean operator + skip_input (); + current_column += 2; + + return Token::make (NOT_EQUAL, loc); + } + else + { + // not equal unary operator + current_column++; + + return Token::make (EXCLAM, loc); + } + case '?': + current_column++; + return Token::make (QUESTION_MARK, loc); + case '#': + current_column++; + return Token::make (HASH, loc); + case '[': + current_column++; + return Token::make (LEFT_SQUARE, loc); + case ']': + current_column++; + return Token::make (RIGHT_SQUARE, loc); + case '{': + current_column++; + return Token::make (LEFT_CURLY, loc); + case '}': + current_column++; + return Token::make (RIGHT_CURLY, loc); + case '@': + current_column++; + return Token::make (PATTERN_BIND, loc); + case '$': + current_column++; + return Token::make (DOLLAR_SIGN, loc); + case '~': + current_column++; + return Token::make (TILDE, loc); + case '\\': + current_column++; + return Token::make (BACKSLASH, loc); + case '`': + current_column++; + return Token::make (BACKTICK, loc); + case '|': + if (peek_input () == '=') + { + // bitwise or-assign? + skip_input (); + current_column += 2; + + return Token::make (PIPE_EQ, loc); + } + else if (peek_input () == '|') + { + // logical or + skip_input (); + current_column += 2; + + return Token::make (OR, loc); + } + else + { + // bitwise or + current_column++; + + return Token::make (PIPE, loc); + } + case '&': + if (peek_input () == '=') + { + // bitwise and-assign? + skip_input (); + current_column += 2; + + return Token::make (AMP_EQ, loc); + } + else if (peek_input () == '&') + { + // logical and + skip_input (); + current_column += 2; + + return Token::make (LOGICAL_AND, loc); + } + else + { + // bitwise and/reference + current_column++; + + return Token::make (AMP, loc); + } + case '.': + if (peek_input () == '.') + { + if (peek_input (1) == '.') + { + // ellipsis + skip_input (1); + current_column += 3; + + return Token::make (ELLIPSIS, loc); + } + else if (peek_input (1) == '=') + { + // ..= + skip_input (1); + current_column += 3; + + return Token::make (DOT_DOT_EQ, loc); + } + else + { + // .. + skip_input (); + current_column += 2; + + return Token::make (DOT_DOT, loc); + } + } + else /*if (!ISDIGIT (peek_input ()))*/ + { + // single dot . + // Only if followed by a non-number - otherwise is float + // nope, float cannot start with '.'. + current_column++; + return Token::make (DOT, loc); + } + } + // TODO: special handling of _ in the lexer? instead of being identifier + + // byte character, byte string and raw byte string literals + if (current_char == 'b') + { + if (peek_input () == '\'') + return parse_byte_char (loc); + else if (peek_input () == '"') + return parse_byte_string (loc); + else if (peek_input () == 'r' + && (peek_input (1) == '#' || peek_input (1) == '"')) + return parse_raw_byte_string (loc); + } + + // raw identifiers and raw strings + if (current_char == 'r') + { + int peek = peek_input (); + int peek1 = peek_input (1); + + if (peek == '#' && (ISALPHA (peek1) || peek1 == '_')) + { + TokenPtr raw_ident_ptr = parse_raw_identifier (loc); + if (raw_ident_ptr != nullptr) + return raw_ident_ptr; + else + continue; /* input got parsed, it just wasn't valid. An error + was produced. */ + } + else + { + TokenPtr maybe_raw_string_ptr = maybe_parse_raw_string (loc); + if (maybe_raw_string_ptr != nullptr) + return maybe_raw_string_ptr; + } + } + + // find identifiers and keywords + if (ISALPHA (current_char) || current_char == '_') + return parse_identifier_or_keyword (loc); + + // int and float literals + if (ISDIGIT (current_char)) + { // _ not allowed as first char + if (current_char == '0' + && is_non_decimal_int_literal_separator (peek_input ())) + { + // handle binary, octal, hex literals + TokenPtr non_dec_int_lit_ptr + = parse_non_decimal_int_literals (loc); + if (non_dec_int_lit_ptr != nullptr) + return non_dec_int_lit_ptr; + } + else + { + // handle decimals (integer or float) + TokenPtr decimal_or_float_ptr = parse_decimal_int_or_float (loc); + if (decimal_or_float_ptr != nullptr) + return decimal_or_float_ptr; + } + } + + // string literals + if (current_char == '"') + return parse_string (loc); + + // char literals and lifetime names + if (current_char == '\'') + { + TokenPtr char_or_lifetime_ptr = parse_char_or_lifetime (loc); + if (char_or_lifetime_ptr != nullptr) + return char_or_lifetime_ptr; + } + + // DEBUG: check for specific character problems: + if (current_char == '0') + rust_debug ("'0' uncaught before unexpected character"); + else if (current_char == ']') + rust_debug ("']' uncaught before unexpected character"); + else if (current_char == 0x5d) + rust_debug ("whatever 0x5d is (not '0' or ']') uncaught before " + "unexpected character"); + + // didn't match anything so error + rust_error_at (loc, "unexpected character %<%x%>", current_char); + current_column++; + } +} + +// Parses in a type suffix. +std::pair +Lexer::parse_in_type_suffix () +{ + std::string suffix; + suffix.reserve (5); + + int additional_length_offset = 0; + + // get suffix + while (ISALPHA (current_char) || ISDIGIT (current_char) + || current_char == '_') + { + if (current_char == '_') + { + // don't add _ to suffix + skip_input (); + current_char = peek_input (); + + additional_length_offset++; + + continue; + } + + additional_length_offset++; + + suffix += current_char; + skip_input (); + current_char = peek_input (); + } + + if (suffix.empty ()) + { + // no type suffix: do nothing but also no error + return std::make_pair (CORETYPE_UNKNOWN, additional_length_offset); + } + else if (suffix == "f32") + { + return std::make_pair (CORETYPE_F32, additional_length_offset); + } + else if (suffix == "f64") + { + return std::make_pair (CORETYPE_F64, additional_length_offset); + } + else if (suffix == "i8") + { + return std::make_pair (CORETYPE_I8, additional_length_offset); + } + else if (suffix == "i16") + { + return std::make_pair (CORETYPE_I16, additional_length_offset); + } + else if (suffix == "i32") + { + return std::make_pair (CORETYPE_I32, additional_length_offset); + } + else if (suffix == "i64") + { + return std::make_pair (CORETYPE_I64, additional_length_offset); + } + else if (suffix == "i128") + { + return std::make_pair (CORETYPE_I128, additional_length_offset); + } + else if (suffix == "isize") + { + return std::make_pair (CORETYPE_ISIZE, additional_length_offset); + } + else if (suffix == "u8") + { + return std::make_pair (CORETYPE_U8, additional_length_offset); + } + else if (suffix == "u16") + { + return std::make_pair (CORETYPE_U16, additional_length_offset); + } + else if (suffix == "u32") + { + return std::make_pair (CORETYPE_U32, additional_length_offset); + } + else if (suffix == "u64") + { + return std::make_pair (CORETYPE_U64, additional_length_offset); + } + else if (suffix == "u128") + { + return std::make_pair (CORETYPE_U128, additional_length_offset); + } + else if (suffix == "usize") + { + return std::make_pair (CORETYPE_USIZE, additional_length_offset); + } + else + { + rust_error_at (get_current_location (), "unknown number suffix %qs", + suffix.c_str ()); + + return std::make_pair (CORETYPE_UNKNOWN, additional_length_offset); + } +} + +// Parses in the exponent part (if any) of a float literal. +std::pair +Lexer::parse_in_exponent_part () +{ + int additional_length_offset = 0; + std::string str; + if (current_char == 'E' || current_char == 'e') + { + // add exponent to string as strtod works with it + str += current_char; + skip_input (); + current_char = peek_input (); + + additional_length_offset++; + + // special - and + handling + if (current_char == '-') + { + str += '-'; + + skip_input (); + current_char = peek_input (); + + additional_length_offset++; + } + else if (current_char == '+') + { + // don't add + but still skip input + skip_input (); + current_char = peek_input (); + + additional_length_offset++; + } + + // parse another decimal number for exponent + auto str_length = parse_in_decimal (); + str += std::get<0> (str_length); + additional_length_offset += std::get<1> (str_length); + } + return std::make_pair (str, additional_length_offset); +} + +// Parses a decimal integer. +std::tuple +Lexer::parse_in_decimal () +{ + /* A pure decimal contains only digits. */ + bool pure_decimal = true; + int additional_length_offset = 0; + std::string str; + while (ISDIGIT (current_char) || current_char == '_') + { + if (current_char == '_') + { + pure_decimal = false; + // don't add _ to number + skip_input (); + current_char = peek_input (); + + additional_length_offset++; + + continue; + } + + additional_length_offset++; + + str += current_char; + skip_input (); + current_char = peek_input (); + } + return std::make_tuple (str, additional_length_offset, pure_decimal); +} + +/* Parses escapes (and string continues) in "byte" strings and characters. Does + * not support unicode. */ +std::tuple +Lexer::parse_escape (char opening_char) +{ + int additional_length_offset = 0; + char output_char = 0; + + // skip to actual letter + skip_input (); + current_char = peek_input (); + additional_length_offset++; + + switch (current_char) + { + case 'x': { + auto hex_escape_pair = parse_partial_hex_escape (); + long hexLong = hex_escape_pair.first; + additional_length_offset += hex_escape_pair.second; + + if (hexLong > 255 || hexLong < 0) + rust_error_at ( + get_current_location (), + "byte \\x escape %<\\x%x%> out of range - allows up to %<\\xFF%>", + static_cast (hexLong)); + /* TODO: restore capital for escape output - gcc pretty-printer doesn't + * support %X directly */ + char hexChar = static_cast (hexLong); + + output_char = hexChar; + } + break; + case 'n': + output_char = '\n'; + break; + case 'r': + output_char = '\r'; + break; + case 't': + output_char = '\t'; + break; + case '\\': + output_char = '\\'; + break; + case '0': + output_char = '\0'; + break; + case '\'': + output_char = '\''; + break; + case '"': + output_char = '"'; + break; + case 'u': + rust_error_at (get_current_location (), + "cannot have a unicode escape \\u in a byte %s", + opening_char == '\'' ? "character" : "string"); + // Try to parse it anyway, just to skip it + parse_partial_unicode_escape (); + return std::make_tuple (output_char, additional_length_offset, false); + case '\r': + case '\n': + // string continue + return std::make_tuple (0, parse_partial_string_continue (), true); + default: + rust_error_at (get_current_location (), + "unknown escape sequence %<\\%c%>", current_char); + // returns false if no parsing could be done + // return false; + return std::make_tuple (output_char, additional_length_offset, false); + break; + } + // all non-special cases (string continue) should skip their used char + skip_input (); + current_char = peek_input (); + additional_length_offset++; + + // returns true if parsing was successful + // return true; + return std::make_tuple (output_char, additional_length_offset, false); +} + +/* Parses an escape (or string continue) in a string or character. Supports + * unicode escapes. */ +std::tuple +Lexer::parse_utf8_escape (char opening_char) +{ + Codepoint output_char; + int additional_length_offset = 0; + + // skip to actual letter + skip_input (); + current_char = peek_input (); + additional_length_offset++; + + switch (current_char) + { + case 'x': { + auto hex_escape_pair = parse_partial_hex_escape (); + long hexLong = hex_escape_pair.first; + additional_length_offset += hex_escape_pair.second; + + if (hexLong > 127 || hexLong < 0) + rust_error_at ( + get_current_location (), + "ascii \\x escape %<\\x%x%> out of range - allows up to %<\\x7F%>", + static_cast (hexLong)); + /* TODO: restore capital for escape output - gcc pretty-printer doesn't + * support %X directly */ + char hexChar = static_cast (hexLong); + + output_char = hexChar; + } + break; + case 'n': + output_char = '\n'; + break; + case 'r': + output_char = '\r'; + break; + case 't': + output_char = '\t'; + break; + case '\\': + output_char = '\\'; + break; + case '0': + output_char = '\0'; + break; + case '\'': + output_char = '\''; + break; + case '"': + output_char = '"'; + break; + case 'u': { + auto unicode_escape_pair = parse_partial_unicode_escape (); + output_char = unicode_escape_pair.first; + additional_length_offset += unicode_escape_pair.second; + + return std::make_tuple (output_char, additional_length_offset, false); + } + break; + case '\r': + case '\n': + // string continue + return std::make_tuple (0, parse_partial_string_continue (), true); + default: + rust_error_at (get_current_location (), + "unknown escape sequence %<\\%c%>", current_char); + // returns false if no parsing could be done + // return false; + return std::make_tuple (output_char, additional_length_offset, false); + break; + } + /* all non-special cases (unicode, string continue) should skip their used + * char */ + skip_input (); + current_char = peek_input (); + additional_length_offset++; + + // returns true if parsing was successful + // return true; + return std::make_tuple (output_char, additional_length_offset, false); +} + +// Parses the body of a string continue that has been found in an escape. +int +Lexer::parse_partial_string_continue () +{ + int additional_length_offset = 1; + + // string continue + while (is_whitespace (current_char)) + { + if (current_char == '\n') + { + current_line++; + current_column = 1; + // tell line_table that new line starts + start_line (current_line, max_column_hint); + + // reset "length" + additional_length_offset = 1; + + // get next char + skip_input (); + current_char = peek_input (); + + continue; + } + + skip_input (); + current_char = peek_input (); + additional_length_offset++; + } + + return additional_length_offset; +} + +/* Parses the body of a '\x' escape. Note that it does not check that the number + * is valid and smaller than 255. */ +std::pair +Lexer::parse_partial_hex_escape () +{ + // hex char string (null-terminated) + char hexNum[3] = {0, 0, 0}; + + // first hex char + current_char = peek_input (1); + int additional_length_offset = 1; + + if (!is_x_digit (current_char)) + { + rust_error_at (get_current_location (), + "invalid character %<\\x%c%> in \\x sequence", + current_char); + return std::make_pair (0, 0); + } + hexNum[0] = current_char; + + // second hex char + skip_input (); + current_char = peek_input (1); + additional_length_offset++; + + if (!is_x_digit (current_char)) + { + rust_error_at (get_current_location (), + "invalid character %<\\x%c%c%> in \\x sequence", hexNum[0], + current_char); + return std::make_pair (0, 1); + } + skip_input (); + hexNum[1] = current_char; + + long hexLong = std::strtol (hexNum, nullptr, 16); + + return std::make_pair (hexLong, additional_length_offset); +} + +// Parses the body of a unicode escape. +std::pair +Lexer::parse_partial_unicode_escape () +{ + skip_input (); + current_char = peek_input (); + int additional_length_offset = 0; + + if (current_char != '{') + { + rust_error_at (get_current_location (), + "unicode escape should start with %<{%>"); + /* Skip what should probaby have been between brackets. */ + while (is_x_digit (current_char) || current_char == '_') + { + skip_input (); + current_char = peek_input (); + additional_length_offset++; + } + return std::make_pair (Codepoint (0), additional_length_offset); + } + + skip_input (); + current_char = peek_input (); + additional_length_offset++; + + if (current_char == '_') + { + rust_error_at (get_current_location (), + "unicode escape cannot start with %<_%>"); + skip_input (); + current_char = peek_input (); + additional_length_offset++; + // fallthrough and try to parse the rest anyway + } + + // parse unicode escape - 1-6 hex digits + std::string num_str; + num_str.reserve (6); + + // loop through to add entire hex number to string + while (is_x_digit (current_char) || current_char == '_') + { + if (current_char == '_') + { + // don't add _ to number + skip_input (); + current_char = peek_input (); + + additional_length_offset++; + + continue; + } + + additional_length_offset++; + + // add raw hex numbers + num_str += current_char; + + skip_input (); + current_char = peek_input (); + } + + if (current_char == '}') + { + skip_input (); + current_char = peek_input (); + additional_length_offset++; + } + else + { + // actually an error, but allow propagation anyway Assume that + // wrong bracketm whitespace or single/double quotes are wrong + // termination, otherwise it is a wrong character, then skip to the actual + // terminator. + if (current_char == '{' || is_whitespace (current_char) + || current_char == '\'' || current_char == '"') + { + rust_error_at (get_current_location (), + "expected terminating %<}%> in unicode escape"); + return std::make_pair (Codepoint (0), additional_length_offset); + } + else + { + rust_error_at (get_current_location (), + "invalid character %<%c%> in unicode escape", + current_char); + while (current_char != '}' && current_char != '{' + && !is_whitespace (current_char) && current_char != '\'' + && current_char != '"') + { + skip_input (); + current_char = peek_input (); + additional_length_offset++; + } + // Consume the actual closing bracket if found + if (current_char == '}') + { + skip_input (); + current_char = peek_input (); + additional_length_offset++; + } + return std::make_pair (Codepoint (0), additional_length_offset); + } + } + + // ensure 1-6 hex characters + if (num_str.length () > 6 || num_str.length () < 1) + { + rust_error_at (get_current_location (), + "unicode escape should be between 1 and 6 hex " + "characters; it is %lu", + (unsigned long) num_str.length ()); + // return false; + return std::make_pair (Codepoint (0), additional_length_offset); + } + + unsigned long hex_num = std::strtoul (num_str.c_str (), nullptr, 16); + + if (hex_num > 0xd7ff && hex_num < 0xe000) + { + rust_error_at ( + get_current_location (), + "unicode escape cannot be a surrogate value (D800 to DFFF)"); + return std::make_pair (Codepoint (0), additional_length_offset); + } + + if (hex_num > 0x10ffff) + { + rust_error_at (get_current_location (), + "unicode escape cannot be larger than 10FFFF"); + return std::make_pair (Codepoint (0), additional_length_offset); + } + + // return true; + return std::make_pair (Codepoint (static_cast (hex_num)), + additional_length_offset); +} + +// Parses a byte character. +TokenPtr +Lexer::parse_byte_char (Location loc) +{ + skip_input (); + current_column++; + // make current char the next character + current_char = peek_input (); + + int length = 1; + + // char to save + char byte_char = 0; + + // detect escapes + if (current_char == '\\') + { + auto escape_length_pair = parse_escape ('\''); + byte_char = std::get<0> (escape_length_pair); + length += std::get<1> (escape_length_pair); + + current_char = peek_input (); + + if (current_char != '\'') + { + rust_error_at (get_current_location (), "unclosed %"); + } + + skip_input (); + current_char = peek_input (); + length++; // go to next char + } + else if (current_char != '\'') + { + // otherwise, get character from direct input character + byte_char = current_char; + + skip_input (); + current_char = peek_input (); + length++; + + if (current_char != '\'') + { + rust_error_at (get_current_location (), "unclosed %"); + } + + skip_input (); + current_char = peek_input (); + length++; // go to next char + } + else + { + rust_error_at (get_current_location (), + "no character inside %<%> for %"); + } + + current_column += length; + + return Token::make_byte_char (loc, byte_char); +} + +// Parses a byte string. +TokenPtr +Lexer::parse_byte_string (Location loc) +{ + // byte string + + // skip quote character + skip_input (); + current_column++; + + std::string str; + str.reserve (16); // some sensible default + + int length = 1; + current_char = peek_input (); + + while (current_char != '"' && current_char != EOF) + { + if (current_char == '\\') + { + auto escape_length_pair = parse_escape ('"'); + char output_char = std::get<0> (escape_length_pair); + + if (output_char == 0 && std::get<2> (escape_length_pair)) + length = std::get<1> (escape_length_pair) - 1; + else + length += std::get<1> (escape_length_pair); + + if (output_char != 0 || !std::get<2> (escape_length_pair)) + str += output_char; + + continue; + } + + length++; + + str += current_char; + skip_input (); + current_char = peek_input (); + } + + current_column += length; + + if (current_char == '"') + { + current_column++; + + skip_input (); + current_char = peek_input (); + } + else if (current_char == EOF) + { + rust_error_at (get_current_location (), "unended byte string literal"); + return Token::make (END_OF_FILE, get_current_location ()); + } + else + { + gcc_unreachable (); + } + + str.shrink_to_fit (); + + return Token::make_byte_string (loc, std::move (str)); +} + +// Parses a raw byte string. +TokenPtr +Lexer::parse_raw_byte_string (Location loc) +{ + // raw byte string literals + std::string str; + str.reserve (16); // some sensible default + + int length = 1; + int hash_count = 0; + + // get hash count at beginnning + skip_input (); + current_char = peek_input (); + length++; + while (current_char == '#') + { + hash_count++; + length++; + + skip_input (); + current_char = peek_input (); + } + + if (current_char != '"') + { + rust_error_at (get_current_location (), + "raw byte string has no opening %<\"%>"); + } + + skip_input (); + current_char = peek_input (); + length++; + + while (true) + { + if (current_char == '"') + { + bool enough_hashes = true; + + for (int i = 0; i < hash_count; i++) + { + if (peek_input (i + 1) != '#') + { + enough_hashes = false; + break; + } + } + + if (enough_hashes) + { + // skip enough input and peek enough input + skip_input (hash_count); + current_char = peek_input (); + length += hash_count + 1; + break; + } + } + + if ((unsigned char) current_char > 127) + { + rust_error_at (get_current_location (), + "character %<%c%> in raw byte string out of range", + current_char); + current_char = 0; + } + + length++; + + str += current_char; + skip_input (); + current_char = peek_input (); + } + + current_column += length; + + str.shrink_to_fit (); + + return Token::make_byte_string (loc, std::move (str)); +} + +// Parses a raw identifier. +TokenPtr +Lexer::parse_raw_identifier (Location loc) +{ + // raw identifier + std::string str; + str.reserve (16); // default + + skip_input (); + current_char = peek_input (); + + current_column += 2; + + bool first_is_underscore = current_char == '_'; + + int length = 0; + current_char = peek_input (); + // loop through entire name + while (ISALPHA (current_char) || ISDIGIT (current_char) + || current_char == '_') + { + length++; + + str += current_char; + skip_input (); + current_char = peek_input (); + } + + current_column += length; + + // if just a single underscore, not an identifier + if (first_is_underscore && length == 1) + rust_error_at (get_current_location (), + "%<_%> is not a valid raw identifier"); + + if (str == "crate" || str == "extern" || str == "self" || str == "super" + || str == "Self") + { + rust_error_at (get_current_location (), + "%qs is a forbidden raw identifier", str.c_str ()); + + return nullptr; + } + else + { + str.shrink_to_fit (); + + return Token::make_identifier (loc, std::move (str)); + } +} + +// skip broken string input (unterminated strings) +void +Lexer::skip_broken_string_input (int current_char) +{ + while (current_char != '"' && current_char != EOF) + { + if (current_char == '\n') + { + current_line++; + current_column = 1; + } + else + { + current_column++; + } + skip_input (); + current_char = peek_input (); + } + if (current_char == '"') + { + current_column++; + + skip_input (); + current_char = peek_input (); + } + rust_debug ("skipped to %d:%d due to bad quotes", current_line, + current_column); +} + +// Parses a unicode string. +TokenPtr +Lexer::parse_string (Location loc) +{ + Codepoint current_char32; + + std::string str; + str.reserve (16); // some sensible default + + int length = 1; + current_char32 = peek_codepoint_input (); + + // FIXME: This fails if the input ends. How do we check for EOF? + while (current_char32.value != '"' && !current_char32.is_eof ()) + { + if (current_char32.value == '\\') + { + // parse escape + auto utf8_escape_pair = parse_utf8_escape ('\''); + current_char32 = std::get<0> (utf8_escape_pair); + + if (current_char32 == Codepoint (0) && std::get<2> (utf8_escape_pair)) + length = std::get<1> (utf8_escape_pair) - 1; + else + length += std::get<1> (utf8_escape_pair); + + if (current_char32 != Codepoint (0) + || !std::get<2> (utf8_escape_pair)) + str += current_char32; + + // required as parsing utf8 escape only changes current_char + current_char32 = peek_codepoint_input (); + + continue; + } + + length += get_input_codepoint_length (); + + str += current_char32; + skip_codepoint_input (); + current_char32 = peek_codepoint_input (); + } + + current_column += length; + + if (current_char32.value == '"') + { + current_column++; + + skip_input (); + current_char = peek_input (); + } + else if (current_char32.is_eof ()) + { + rust_error_at (get_current_location (), "unended string literal"); + return Token::make (END_OF_FILE, get_current_location ()); + } + else + { + gcc_unreachable (); + } + + str.shrink_to_fit (); + return Token::make_string (loc, std::move (str)); +} + +// Parses an identifier or keyword. +TokenPtr +Lexer::parse_identifier_or_keyword (Location loc) +{ + std::string str; + str.reserve (16); // default + str += current_char; + + bool first_is_underscore = current_char == '_'; + + int length = 1; + current_char = peek_input (); + // loop through entire name + while (ISALPHA (current_char) || ISDIGIT (current_char) + || current_char == '_') + { + length++; + + str += current_char; + skip_input (); + current_char = peek_input (); + } + + current_column += length; + + // if just a single underscore, not an identifier + if (first_is_underscore && length == 1) + return Token::make (UNDERSCORE, loc); + + str.shrink_to_fit (); + + TokenId keyword = classify_keyword (str); + if (keyword == IDENTIFIER) + return Token::make_identifier (loc, std::move (str)); + else + return Token::make (keyword, loc); +} + +// Possibly returns a raw string token if it exists - otherwise returns null. +TokenPtr +Lexer::maybe_parse_raw_string (Location loc) +{ + int peek_index = 0; + while (peek_input (peek_index) == '#') + peek_index++; + + if (peek_input (peek_index) == '"') + return parse_raw_string (loc, peek_index); + else + return nullptr; +} + +// Returns a raw string token. +TokenPtr +Lexer::parse_raw_string (Location loc, int initial_hash_count) +{ + // raw string literals + std::string str; + str.reserve (16); // some sensible default + + int length = 1 + initial_hash_count; + + if (initial_hash_count > 0) + skip_input (initial_hash_count - 1); + + current_char = peek_input (); + + if (current_char != '"') + rust_error_at (get_current_location (), "raw string has no opening %<\"%>"); + + length++; + skip_input (); + Codepoint current_char32 = peek_codepoint_input (); + + while (!current_char32.is_eof ()) + { + if (current_char32.value == '"') + { + bool enough_hashes = true; + + for (int i = 0; i < initial_hash_count; i++) + { + if (peek_input (i + 1) != '#') + { + enough_hashes = false; + break; + } + } + + if (enough_hashes) + { + // skip enough input and peek enough input + skip_input (initial_hash_count); + current_char = peek_input (); + length += initial_hash_count + 1; + break; + } + } + + length++; + + str += current_char32; + skip_codepoint_input (); + current_char32 = peek_codepoint_input (); + } + + current_column += length; + + str.shrink_to_fit (); + + return Token::make_string (loc, std::move (str)); +} + +template +TokenPtr +Lexer::parse_non_decimal_int_literal (Location loc, IsDigitFunc is_digit_func, + std::string existent_str, int base) +{ + int length = 1; + + skip_input (); + current_char = peek_input (); + + length++; + + // loop through to add entire number to string + while (is_digit_func (current_char) || current_char == '_') + { + if (current_char == '_') + { + // don't add _ to number + skip_input (); + current_char = peek_input (); + + length++; + + continue; + } + + length++; + + // add raw numbers + existent_str += current_char; + skip_input (); + current_char = peek_input (); + } + + // convert value to decimal representation + long dec_num = std::strtol (existent_str.c_str (), nullptr, base); + + existent_str = std::to_string (dec_num); + + // parse in type suffix if it exists + auto type_suffix_pair = parse_in_type_suffix (); + PrimitiveCoreType type_hint = type_suffix_pair.first; + length += type_suffix_pair.second; + + current_column += length; + + if (type_hint == CORETYPE_F32 || type_hint == CORETYPE_F64) + { + rust_error_at (get_current_location (), + "invalid type suffix %qs for integer (%s) literal", + get_type_hint_string (type_hint), + base == 16 + ? "hex" + : (base == 8 ? "octal" + : (base == 2 ? "binary" + : ""))); + return nullptr; + } + return Token::make_int (loc, std::move (existent_str), type_hint); +} + +// Parses a hex, binary or octal int literal. +TokenPtr +Lexer::parse_non_decimal_int_literals (Location loc) +{ + std::string str; + str.reserve (16); // some sensible default + str += current_char; + + current_char = peek_input (); + + if (current_char == 'x') + { + // hex (integer only) + return parse_non_decimal_int_literal (loc, is_x_digit, str + "x", 16); + } + else if (current_char == 'o') + { + // octal (integer only) + return parse_non_decimal_int_literal (loc, is_octal_digit, + std::move (str), 8); + } + else if (current_char == 'b') + { + // binary (integer only) + return parse_non_decimal_int_literal (loc, is_bin_digit, std::move (str), + 2); + } + else + { + return nullptr; + } +} + +// Parses a decimal-based int literal or float literal. +TokenPtr +Lexer::parse_decimal_int_or_float (Location loc) +{ + std::string str; + str.reserve (16); // some sensible default + str += current_char; + + int length = 1; + bool first_zero = current_char == '0'; + + current_char = peek_input (); + + // parse initial decimal integer (or first integer part of float) literal + auto initial_decimal = parse_in_decimal (); + str += std::get<0> (initial_decimal); + length += std::get<1> (initial_decimal); + + // detect float literal + if (current_char == '.' && is_float_digit (peek_input (1))) + { + // float with a '.', parse another decimal into it + + // add . to str + str += current_char; + skip_input (); + current_char = peek_input (); + length++; + + // parse another decimal number for float + auto second_decimal = parse_in_decimal (); + str += std::get<0> (second_decimal); + length += std::get<1> (second_decimal); + + // parse in exponent part if it exists + auto exponent_pair = parse_in_exponent_part (); + str += exponent_pair.first; + length += exponent_pair.second; + + // parse in type suffix if it exists + auto type_suffix_pair = parse_in_type_suffix (); + PrimitiveCoreType type_hint = type_suffix_pair.first; + length += type_suffix_pair.second; + + if (type_hint != CORETYPE_F32 && type_hint != CORETYPE_F64 + && type_hint != CORETYPE_UNKNOWN) + { + rust_error_at (get_current_location (), + "invalid type suffix %qs for floating-point literal", + get_type_hint_string (type_hint)); + // ignore invalid type suffix as everything else seems fine + type_hint = CORETYPE_UNKNOWN; + } + + current_column += length; + + str.shrink_to_fit (); + return Token::make_float (loc, std::move (str), type_hint); + } + else if (current_char == '.' && check_valid_float_dot_end (peek_input (1))) + { + // float that is just an integer with a terminating '.' character + + // add . to str + str += current_char; + skip_input (); + current_char = peek_input (); + length++; + + // add a '0' after the . to prevent ambiguity + str += '0'; + + // type hint not allowed + + current_column += length; + + str.shrink_to_fit (); + return Token::make_float (loc, std::move (str), CORETYPE_UNKNOWN); + } + else if (current_char == 'E' || current_char == 'e') + { + // exponent float with no '.' character + + // parse exponent part + auto exponent_pair = parse_in_exponent_part (); + str += exponent_pair.first; + length += exponent_pair.second; + + // parse in type suffix if it exists + auto type_suffix_pair = parse_in_type_suffix (); + PrimitiveCoreType type_hint = type_suffix_pair.first; + length += type_suffix_pair.second; + + if (type_hint != CORETYPE_F32 && type_hint != CORETYPE_F64 + && type_hint != CORETYPE_UNKNOWN) + { + rust_error_at (get_current_location (), + "invalid type suffix %qs for floating-point literal", + get_type_hint_string (type_hint)); + // ignore invalid type suffix as everything else seems fine + type_hint = CORETYPE_UNKNOWN; + } + + current_column += length; + + str.shrink_to_fit (); + return Token::make_float (loc, std::move (str), type_hint); + } + else + { + // is an integer + + // parse in type suffix if it exists + auto type_suffix_pair = parse_in_type_suffix (); + PrimitiveCoreType type_hint = type_suffix_pair.first; + /* A "real" pure decimal doesn't have a suffix and no zero prefix. */ + if (type_hint == CORETYPE_UNKNOWN) + { + bool pure_decimal = std::get<2> (initial_decimal); + if (pure_decimal && (!first_zero || str.size () == 1)) + type_hint = CORETYPE_PURE_DECIMAL; + } + length += type_suffix_pair.second; + + current_column += length; + + str.shrink_to_fit (); + return Token::make_int (loc, std::move (str), type_hint); + } +} + +TokenPtr +Lexer::parse_char_or_lifetime (Location loc) +{ + Codepoint current_char32; + + int length = 1; + + current_char32 = peek_codepoint_input (); + if (current_char32.is_eof ()) + return nullptr; + + // parse escaped char literal + if (current_char32.value == '\\') + { + // parse escape + auto utf8_escape_pair = parse_utf8_escape ('\''); + current_char32 = std::get<0> (utf8_escape_pair); + length += std::get<1> (utf8_escape_pair); + + if (peek_codepoint_input ().value != '\'') + { + rust_error_at (get_current_location (), "unended character literal"); + } + else + { + skip_codepoint_input (); + current_char = peek_input (); + length++; + } + + current_column += length; + + return Token::make_char (loc, current_char32); + } + else + { + skip_codepoint_input (); + + if (peek_codepoint_input ().value == '\'') + { + // parse non-escaped char literal + + // skip the ' character + skip_input (); + current_char = peek_input (); + + // TODO fix due to different widths of utf-8 chars? + current_column += 3; + + return Token::make_char (loc, current_char32); + } + else if (ISDIGIT (current_char32.value) || ISALPHA (current_char32.value) + || current_char32.value == '_') + { + // parse lifetime name + std::string str; + str += current_char32; + length++; + + current_char = peek_input (); + while (ISDIGIT (current_char) || ISALPHA (current_char) + || current_char == '_') + { + str += current_char; + skip_input (); + current_char = peek_input (); + length++; + } + + current_column += length; + + str.shrink_to_fit (); + return Token::make_lifetime (loc, std::move (str)); + } + else + { + rust_error_at ( + get_current_location (), + "expected %' after character constant in character literal"); + return nullptr; + } + } +} + +// Returns the length of the codepoint at the current position. +int +Lexer::get_input_codepoint_length () +{ + uint8_t input = peek_input (); + + if ((int8_t) input == EOF) + return 0; + + if (input < 128) + { + // ascii -- 1 byte + // return input; + + return 1; + } + else if ((input & 0xC0) == 0x80) + { + // invalid (continuation; can't be first char) + // return 0xFFFE; + + return 0; + } + else if ((input & 0xE0) == 0xC0) + { + // 2 bytes + uint8_t input2 = peek_input (1); + if ((input2 & 0xC0) != 0x80) + return 0; + // return 0xFFFE; + + // uint32_t output = ((input & 0x1F) << 6) | ((input2 & 0x3F) << 0); + // return output; + return 2; + } + else if ((input & 0xF0) == 0xE0) + { + // 3 bytes + uint8_t input2 = peek_input (1); + if ((input2 & 0xC0) != 0x80) + return 0; + // return 0xFFFE; + + uint8_t input3 = peek_input (2); + if ((input3 & 0xC0) != 0x80) + return 0; + // return 0xFFFE; + + /*uint32_t output + = ((input & 0x0F) << 12) | ((input2 & 0x3F) << 6) | ((input3 & 0x3F) << + 0); return output;*/ + return 3; + } + else if ((input & 0xF8) == 0xF0) + { + // 4 bytes + uint8_t input2 = peek_input (1); + if ((input2 & 0xC0) != 0x80) + return 0; + // return 0xFFFE; + + uint8_t input3 = peek_input (2); + if ((input3 & 0xC0) != 0x80) + return 0; + // return 0xFFFE; + + uint8_t input4 = peek_input (3); + if ((input4 & 0xC0) != 0x80) + return 0; + // return 0xFFFE; + + /*uint32_t output = ((input & 0x07) << 18) | ((input2 & 0x3F) << 12) + | ((input3 & 0x3F) << 6) | ((input4 & 0x3F) << 0); + return output;*/ + return 4; + } + else + { + rust_error_at (get_current_location (), + "invalid UTF-8 [FIRST] (too long)"); + return 0; + } +} + +// Returns the codepoint at the current position. +Codepoint +Lexer::peek_codepoint_input () +{ + uint8_t input = peek_input (); + + if ((int8_t) input == EOF) + return Codepoint::eof (); + + if (input < 128) + { + // ascii -- 1 byte + return {input}; + } + else if ((input & 0xC0) == 0x80) + { + // invalid (continuation; can't be first char) + return {0xFFFE}; + } + else if ((input & 0xE0) == 0xC0) + { + // 2 bytes + uint8_t input2 = peek_input (1); + if ((input2 & 0xC0) != 0x80) + return {0xFFFE}; + + uint32_t output = ((input & 0x1F) << 6) | ((input2 & 0x3F) << 0); + return {output}; + } + else if ((input & 0xF0) == 0xE0) + { + // 3 bytes + uint8_t input2 = peek_input (1); + if ((input2 & 0xC0) != 0x80) + return {0xFFFE}; + + uint8_t input3 = peek_input (2); + if ((input3 & 0xC0) != 0x80) + return {0xFFFE}; + + uint32_t output = ((input & 0x0F) << 12) | ((input2 & 0x3F) << 6) + | ((input3 & 0x3F) << 0); + return {output}; + } + else if ((input & 0xF8) == 0xF0) + { + // 4 bytes + uint8_t input2 = peek_input (1); + if ((input2 & 0xC0) != 0x80) + return {0xFFFE}; + + uint8_t input3 = peek_input (2); + if ((input3 & 0xC0) != 0x80) + return {0xFFFE}; + + uint8_t input4 = peek_input (3); + if ((input4 & 0xC0) != 0x80) + return {0xFFFE}; + + uint32_t output = ((input & 0x07) << 18) | ((input2 & 0x3F) << 12) + | ((input3 & 0x3F) << 6) | ((input4 & 0x3F) << 0); + return {output}; + } + else + { + rust_error_at (get_current_location (), + "invalid UTF-8 [SECND] (too long)"); + return {0xFFFE}; + } +} + +void +Lexer::skip_codepoint_input () +{ + int toSkip = get_input_codepoint_length (); + gcc_assert (toSkip >= 1); + + skip_input (toSkip - 1); +} + +int +Lexer::test_get_input_codepoint_n_length (int n_start_offset) +{ + uint8_t input = peek_input (n_start_offset); + + if (input < 128) + { + // ascii -- 1 byte + // return input; + return 1; + } + else if ((input & 0xC0) == 0x80) + { + // invalid (continuation; can't be first char) + // return 0xFFFE; + return 0; + } + else if ((input & 0xE0) == 0xC0) + { + // 2 bytes + uint8_t input2 = peek_input (n_start_offset + 1); + if ((input2 & 0xC0) != 0x80) + // return 0xFFFE; + return 0; + + // uint32_t output = ((input & 0x1F) << 6) | ((input2 & 0x3F) << 0); + // return output; + return 2; + } + else if ((input & 0xF0) == 0xE0) + { + // 3 bytes + uint8_t input2 = peek_input (n_start_offset + 1); + if ((input2 & 0xC0) != 0x80) + // return 0xFFFE; + return 0; + + uint8_t input3 = peek_input (n_start_offset + 2); + if ((input3 & 0xC0) != 0x80) + // return 0xFFFE; + return 0; + + /*uint32_t output + = ((input & 0x0F) << 12) | ((input2 & 0x3F) << 6) | ((input3 & 0x3F) << + 0); return output;*/ + return 3; + } + else if ((input & 0xF8) == 0xF0) + { + // 4 bytes + uint8_t input2 = peek_input (n_start_offset + 1); + if ((input2 & 0xC0) != 0x80) + // return 0xFFFE; + return 0; + + uint8_t input3 = peek_input (n_start_offset + 2); + if ((input3 & 0xC0) != 0x80) + // return 0xFFFE; + return 0; + + uint8_t input4 = peek_input (n_start_offset + 3); + if ((input4 & 0xC0) != 0x80) + // return 0xFFFE; + return 0; + + /*uint32_t output = ((input & 0x07) << 18) | ((input2 & 0x3F) << 12) + | ((input3 & 0x3F) << 6) | ((input4 & 0x3F) << 0); + return output;*/ + return 4; + } + else + { + rust_error_at (get_current_location (), + "invalid UTF-8 [THIRD] (too long)"); + return 0; + } +} + +// peeks the codepoint input at n codepoints ahead of current codepoint - try +// not to use +Codepoint +Lexer::test_peek_codepoint_input (int n) +{ + int totalOffset = 0; + + // add up all offsets into total offset? does this do what I want? + for (int i = 0; i < n; i++) + { + totalOffset += test_get_input_codepoint_n_length (totalOffset); + } + // issues: this would have (at least) O(n) lookup time, not O(1) like the + // rest? + + // TODO: implement if still needed + + // error out of function as it is not implemented + gcc_assert (1 == 0); + return {0}; + /* + uint8_t input = peek_input(); + + if (input < 128) { + // ascii -- 1 byte + return input; + } else if ((input & 0xC0) == 0x80) { + // invalid (continuation; can't be first char) + return 0xFFFE; + } else if ((input & 0xE0) == 0xC0) { + // 2 bytes + uint8_t input2 = peek_input(1); + if ((input2 & 0xC0) != 0x80) + return 0xFFFE; + + uint32_t output = ((input & 0x1F) << 6) | ((input2 & 0x3F) << 0); + return output; + } else if ((input & 0xF0) == 0xE0) { + // 3 bytes + uint8_t input2 = peek_input(1); + if ((input2 & 0xC0) != 0x80) + return 0xFFFE; + + uint8_t input3 = peek_input(2); + if ((input3 & 0xC0) != 0x80) + return 0xFFFE; + + uint32_t output + = ((input & 0x0F) << 12) | ((input2 & 0x3F) << 6) | ((input3 & + 0x3F) << 0); return output; } else if ((input & 0xF8) == 0xF0) { + // 4 bytes + uint8_t input2 = peek_input(1); + if ((input2 & 0xC0) != 0x80) + return 0xFFFE; + + uint8_t input3 = peek_input(2); + if ((input3 & 0xC0) != 0x80) + return 0xFFFE; + + uint8_t input4 = peek_input(3); + if ((input4 & 0xC0) != 0x80) + return 0xFFFE; + + uint32_t output = ((input & 0x07) << 18) | ((input2 & 0x3F) << 12) + | ((input3 & 0x3F) << 6) | ((input4 & 0x3F) << + 0); return output; } else { rust_error_at(get_current_location(), "invalid + UTF-8 (too long)"); return 0xFFFE; + }*/ +} + +void +Lexer::split_current_token (TokenId new_left, TokenId new_right) +{ + /* TODO: assert that this TokenId is a "simple token" like punctuation and not + * like "IDENTIFIER"? */ + Location current_loc = peek_token ()->get_locus (); + TokenPtr new_left_tok = Token::make (new_left, current_loc); + TokenPtr new_right_tok = Token::make (new_right, current_loc + 1); + + token_queue.replace_current_value (std::move (new_left_tok)); + token_queue.insert (1, std::move (new_right_tok)); +} + +void +Lexer::start_line (int current_line, int current_column) +{ + if (line_map) + line_map->start_line (current_line, current_column); +} + +} // namespace Rust diff --git a/gcc/rust/lex/rust-lex.h b/gcc/rust/lex/rust-lex.h new file mode 100644 index 00000000000..d5a6c53719f --- /dev/null +++ b/gcc/rust/lex/rust-lex.h @@ -0,0 +1,271 @@ +// 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_LEX_H +#define RUST_LEX_H + +#include "rust-linemap.h" +#include "rust-buffered-queue.h" +#include "rust-token.h" + +namespace Rust { +// Simple wrapper for FILE* that simplifies destruction. +struct RAIIFile +{ +private: + FILE *file; + const char *filename; + + void close () + { + if (file != nullptr && file != stdin) + fclose (file); + } + +public: + RAIIFile (const char *filename) : filename (filename) + { + if (strcmp (filename, "-") == 0) + file = stdin; + else + file = fopen (filename, "r"); + } + + /** + * Create a RAIIFile from an existing instance of FILE* + */ + RAIIFile (FILE *raw, const char *filename = nullptr) + : file (raw), filename (filename) + {} + + RAIIFile (const RAIIFile &other) = delete; + RAIIFile &operator= (const RAIIFile &other) = delete; + + // have to specify setting file to nullptr, otherwise unintended fclose occurs + RAIIFile (RAIIFile &&other) : file (other.file), filename (other.filename) + { + other.file = nullptr; + } + + RAIIFile &operator= (RAIIFile &&other) + { + close (); + file = other.file; + filename = other.filename; + other.file = nullptr; + + return *this; + } + + static RAIIFile create_error () { return RAIIFile (nullptr, nullptr); } + + ~RAIIFile () { close (); } + + FILE *get_raw () { return file; } + const char *get_filename () { return filename; } + + bool ok () const { return file; } +}; + +class Lexer +{ +private: + // Request new Location for current column in line_table + Location get_current_location (); + + // Skips the current input char. + void skip_input (); + // Advances current input char to n + 1 chars ahead of current position. + void skip_input (int n); + + // Returns char n chars ahead of current position. + int peek_input (); + // Peeks the current char. + int peek_input (int n); + + // Classifies keyword (i.e. gets id for keyword). + TokenId classify_keyword (const std::string &str); + + // Builds a token from the input queue. + TokenPtr build_token (); + + std::tuple parse_in_decimal (); + std::pair parse_in_exponent_part (); + std::pair parse_in_type_suffix (); + std::tuple parse_escape (char opening_char); + std::tuple parse_utf8_escape (char opening_char); + int parse_partial_string_continue (); + std::pair parse_partial_hex_escape (); + std::pair parse_partial_unicode_escape (); + + int get_input_codepoint_length (); + int test_get_input_codepoint_n_length (int n_start_offset); + Codepoint peek_codepoint_input (); + Codepoint test_peek_codepoint_input (int n); + void skip_codepoint_input (); + void skip_broken_string_input (int current_char); + + TokenPtr parse_byte_char (Location loc); + TokenPtr parse_byte_string (Location loc); + TokenPtr parse_raw_byte_string (Location loc); + TokenPtr parse_raw_identifier (Location loc); + TokenPtr parse_string (Location loc); + TokenPtr maybe_parse_raw_string (Location loc); + TokenPtr parse_raw_string (Location loc, int initial_hash_count); + TokenPtr parse_non_decimal_int_literals (Location loc); + TokenPtr parse_decimal_int_or_float (Location loc); + TokenPtr parse_char_or_lifetime (Location loc); + TokenPtr parse_identifier_or_keyword (Location loc); + + template + TokenPtr parse_non_decimal_int_literal (Location loc, + IsDigitFunc is_digit_func, + std::string existent_str, int base); + +public: + // Construct lexer with input file and filename provided + Lexer (const char *filename, RAIIFile input, Linemap *linemap); + + // Lex the contents of a string instead of a file + Lexer (const std::string &input); + + // dtor + ~Lexer (); + + // don't allow copy semantics (for now, at least) + Lexer (const Lexer &other) = delete; + Lexer &operator= (const Lexer &other) = delete; + + // enable move semantics + Lexer (Lexer &&other) = default; + Lexer &operator= (Lexer &&other) = default; + + // Returns token n tokens ahead of current position. + const_TokenPtr peek_token (int n) { return token_queue.peek (n); } + // Peeks the current token. + const_TokenPtr peek_token () { return peek_token (0); } + + // Advances current token to n + 1 tokens ahead of current position. + void skip_token (int n) { token_queue.skip (n); } + // Skips the current token. + void skip_token () { skip_token (0); } + + // Replaces the current token with a specified token. + void replace_current_token (TokenPtr replacement); + // FIXME: don't use anymore + + /* Splits the current token into two. Intended for use with nested generics + * closes (i.e. T> where >> is wrongly lexed as one token). Note that + * this will only work with "simple" tokens like punctuation. */ + void split_current_token (TokenId new_left, TokenId new_right); + + Linemap *get_line_map () { return line_map; } + std::string get_filename () { return std::string (input.get_filename ()); } + +private: + void start_line (int current_line, int current_column); + + // File for use as input. + RAIIFile input; + // TODO is this actually required? could just have file storage in InputSource + + // Current line number. + int current_line; + // Current column number. + int current_column; + // Current character. + int current_char; + // Line map. + Linemap *line_map; + + /* Max column number that can be quickly allocated - higher may require + * allocating new linemap */ + static const int max_column_hint = 80; + + // Input source wrapper thing. + class InputSource + { + public: + virtual ~InputSource () {} + + // Overload operator () to return next char from input stream. + virtual int next () = 0; + }; + + class FileInputSource : public InputSource + { + private: + // Input source file. + FILE *input; + + public: + // Create new input source from file. + FileInputSource (FILE *input) : input (input) {} + + int next () override { return fgetc (input); } + }; + + class BufferInputSource : public InputSource + { + private: + const std::string &buffer; + size_t offs; + + public: + // Create new input source from file. + BufferInputSource (const std::string &b, size_t offset) + : buffer (b), offs (offset) + {} + + int next () override + { + if (offs >= buffer.size ()) + return EOF; + + return buffer.at (offs++); + } + }; + + // The input source for the lexer. + // InputSource input_source; + // Input file queue. + std::unique_ptr raw_input_source; + buffered_queue input_queue; + + // Token source wrapper thing. + struct TokenSource + { + // The lexer object that will use this TokenSource. + Lexer *lexer; + + // Create a new TokenSource with given lexer. + TokenSource (Lexer *parLexer) : lexer (parLexer) {} + + // Overload operator () to build token in lexer. + TokenPtr next () { return lexer->build_token (); } + }; + + // The token source for the lexer. + // TokenSource token_source; + // Token stream queue. + buffered_queue, TokenSource> token_queue; +}; + +} // namespace Rust + +#endif diff --git a/gcc/rust/lex/rust-token.cc b/gcc/rust/lex/rust-token.cc new file mode 100644 index 00000000000..68313c20b1c --- /dev/null +++ b/gcc/rust/lex/rust-token.cc @@ -0,0 +1,135 @@ +// 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 +// . + +#include "rust-token.h" + +#include "rust-diagnostics.h" // for error_at + +namespace Rust { +// Hackily defined way to get token description for enum value using x-macros +const char * +get_token_description (TokenId id) +{ + switch (id) + { +#define RS_TOKEN(name, descr) \ + case name: \ + return descr; +#define RS_TOKEN_KEYWORD(x, y) RS_TOKEN (x, y) + RS_TOKEN_LIST +#undef RS_TOKEN_KEYWORD +#undef RS_TOKEN + default: + gcc_unreachable (); + } +} + +/* Hackily defined way to get token description as a string for enum value using + * x-macros */ +const char * +token_id_to_str (TokenId id) +{ + switch (id) + { +#define RS_TOKEN(name, _) \ + case name: \ + return #name; +#define RS_TOKEN_KEYWORD(x, y) RS_TOKEN (x, y) + RS_TOKEN_LIST +#undef RS_TOKEN_KEYWORD +#undef RS_TOKEN + default: + gcc_unreachable (); + } +} + +const char * +get_type_hint_string (PrimitiveCoreType type) +{ + switch (type) + { + case CORETYPE_BOOL: + return "bool"; + case CORETYPE_CHAR: + return "char"; + case CORETYPE_STR: + return "str"; + // case CORETYPE_INT: + case CORETYPE_ISIZE: + return "isize"; + // case CORETYPE_UINT: + case CORETYPE_USIZE: + return "usize"; + case CORETYPE_F32: + return "f32"; + case CORETYPE_F64: + return "f64"; + case CORETYPE_I8: + return "i8"; + case CORETYPE_I16: + return "i16"; + case CORETYPE_I32: + return "i32"; + case CORETYPE_I64: + return "i64"; + case CORETYPE_I128: + return "i128"; + case CORETYPE_U8: + return "u8"; + case CORETYPE_U16: + return "u16"; + case CORETYPE_U32: + return "u32"; + case CORETYPE_U64: + return "u64"; + case CORETYPE_U128: + return "u128"; + case CORETYPE_PURE_DECIMAL: + return "pure_decimal"; + case CORETYPE_UNKNOWN: + default: + return "unknown"; + } +} + +const char * +Token::get_type_hint_str () const +{ + return get_type_hint_string (type_hint); +} + +const std::string & +Token::get_str () const +{ + // FIXME: attempt to return null again + // gcc_assert(str != NULL); + + // HACK: allow referencing an empty string + static const std::string empty = ""; + + if (str == NULL) + { + rust_error_at (get_locus (), + "attempted to get string for %<%s%>, which has no string. " + "returning empty string instead", + get_token_description ()); + return empty; + } + return *str; +} +} // namespace Rust diff --git a/gcc/rust/lex/rust-token.h b/gcc/rust/lex/rust-token.h new file mode 100644 index 00000000000..3fa46a2cebe --- /dev/null +++ b/gcc/rust/lex/rust-token.h @@ -0,0 +1,455 @@ +// 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_TOKEN_H +#define RUST_TOKEN_H + +#include "rust-linemap.h" +#include "rust-codepoint.h" + +// order: config, system, coretypes, input +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "input.h" + +namespace Rust { +// "Primitive core types" in Rust - the different int and float types, as well +// as some others +enum PrimitiveCoreType +{ + CORETYPE_UNKNOWN, + // named primitives + CORETYPE_BOOL, + CORETYPE_CHAR, + CORETYPE_STR, + // okay technically int and uint are arch-dependent (pointer size) + CORETYPE_INT, + CORETYPE_UINT, + // numbered number primitives + CORETYPE_F32, + CORETYPE_F64, + CORETYPE_I8, + CORETYPE_I16, + CORETYPE_I32, + CORETYPE_I64, + CORETYPE_I128, + CORETYPE_U8, + CORETYPE_U16, + CORETYPE_U32, + CORETYPE_U64, + CORETYPE_U128, + // Pure decimals are used for tuple index. + // Also means there is no type hint. + CORETYPE_PURE_DECIMAL, + // arch-dependent pointer sizes + CORETYPE_ISIZE = CORETYPE_INT, + CORETYPE_USIZE = CORETYPE_UINT +}; + +// RS_TOKEN(name, description) +// RS_TOKEN_KEYWORD(name, identifier) +// +// Keep RS_TOKEN_KEYWORD sorted + +/* note that abstract, async, become, box, do, final, macro, override, priv, + * try, typeof, unsized, virtual, and yield are unused */ +#define RS_TOKEN_LIST \ + RS_TOKEN (FIRST_TOKEN, "") \ + RS_TOKEN (END_OF_FILE, "end of file") \ + RS_TOKEN (EXCLAM, "!") \ + RS_TOKEN (NOT_EQUAL, "!=") \ + RS_TOKEN (PERCENT, "%") \ + RS_TOKEN (PERCENT_EQ, "%=") \ + RS_TOKEN (AMP, "&") \ + RS_TOKEN (AMP_EQ, "&=") \ + RS_TOKEN (LOGICAL_AND, "&&") \ + RS_TOKEN (ASTERISK, "*") \ + RS_TOKEN (ASTERISK_EQ, "*=") \ + RS_TOKEN (PLUS, "+") \ + RS_TOKEN (PLUS_EQ, "+=") \ + RS_TOKEN (COMMA, ",") \ + RS_TOKEN (MINUS, "-") \ + RS_TOKEN (MINUS_EQ, "-=") \ + RS_TOKEN (RETURN_TYPE, "->") \ + RS_TOKEN (DOT, ".") \ + RS_TOKEN (DOT_DOT, "..") \ + RS_TOKEN (DOT_DOT_EQ, "..=") \ + RS_TOKEN (ELLIPSIS, "...") \ + RS_TOKEN (DIV, "/") \ + RS_TOKEN (DIV_EQ, "/=") \ + RS_TOKEN (COLON, ":") \ + RS_TOKEN (SEMICOLON, ";") \ + RS_TOKEN (LEFT_SHIFT, "<<") \ + RS_TOKEN (LEFT_SHIFT_EQ, "<<=") \ + RS_TOKEN (LEFT_ANGLE, "<") \ + RS_TOKEN (LESS_OR_EQUAL, "<=") \ + RS_TOKEN (EQUAL, "=") \ + RS_TOKEN (EQUAL_EQUAL, "==") \ + RS_TOKEN (MATCH_ARROW, "=>") \ + RS_TOKEN (RIGHT_ANGLE, ">") \ + RS_TOKEN (GREATER_OR_EQUAL, ">=") \ + RS_TOKEN (RIGHT_SHIFT, ">>") \ + RS_TOKEN (RIGHT_SHIFT_EQ, ">>=") \ + RS_TOKEN (PATTERN_BIND, "@") \ + RS_TOKEN (TILDE, "~") \ + RS_TOKEN (BACKSLASH, "\\") \ + RS_TOKEN (BACKTICK, "`") \ + RS_TOKEN (CARET, "^") \ + RS_TOKEN (CARET_EQ, "^=") \ + RS_TOKEN (PIPE, "|") \ + RS_TOKEN (PIPE_EQ, "|=") \ + RS_TOKEN (OR, "||") \ + RS_TOKEN (QUESTION_MARK, "?") \ + RS_TOKEN (HASH, "#") \ + /* from here on, dodgy and may not be correct. not operators and may be \ + * symbols */ \ + /* RS_TOKEN(SPACE, " ") probably too dodgy */ \ + /* RS_TOKEN(NEWLINE, "\n")*/ \ + RS_TOKEN (SCOPE_RESOLUTION, "::") /* dodgy */ \ + RS_TOKEN (SINGLE_QUOTE, "'") /* should i differentiate from lifetime? */ \ + RS_TOKEN (DOUBLE_QUOTE, "\"") \ + RS_TOKEN (UNDERSCORE, \ + "_") /* TODO: treat as reserved word like mrustc instead? */ \ + RS_TOKEN (IDENTIFIER, "identifier") \ + RS_TOKEN (INT_LITERAL, \ + "integer literal") /* do different int and float types need \ + different literal types? */ \ + RS_TOKEN (FLOAT_LITERAL, "float literal") \ + RS_TOKEN (STRING_LITERAL, "string literal") \ + RS_TOKEN (CHAR_LITERAL, "character literal") \ + RS_TOKEN (BYTE_STRING_LITERAL, "byte string literal") \ + RS_TOKEN (BYTE_CHAR_LITERAL, "byte character literal") \ + RS_TOKEN (LIFETIME, "lifetime") /* TODO: improve token type */ \ + /* Have "interpolated" tokens (whatever that means)? identifer, path, type, \ + * pattern, */ \ + /* expression, statement, block, meta, item in mrustc (but not directly in \ + * lexer). */ \ + RS_TOKEN (LEFT_PAREN, "(") \ + RS_TOKEN (RIGHT_PAREN, ")") \ + RS_TOKEN (LEFT_CURLY, "{") \ + RS_TOKEN (RIGHT_CURLY, "}") \ + RS_TOKEN (LEFT_SQUARE, "[") \ + RS_TOKEN (RIGHT_SQUARE, "]") \ + /* Macros */ \ + RS_TOKEN (DOLLAR_SIGN, "$") \ + /* Doc Comments */ \ + RS_TOKEN (INNER_DOC_COMMENT, "#![doc]") \ + RS_TOKEN (OUTER_DOC_COMMENT, "#[doc]") \ + /* have "weak" union and 'static keywords? */ \ + \ + RS_TOKEN_KEYWORD (ABSTRACT, "abstract") /* unused */ \ + RS_TOKEN_KEYWORD (AS, "as") \ + RS_TOKEN_KEYWORD (ASYNC, "async") /* unused */ \ + RS_TOKEN_KEYWORD (BECOME, "become") /* unused */ \ + RS_TOKEN_KEYWORD (BOX, "box") /* unused */ \ + RS_TOKEN_KEYWORD (BREAK, "break") \ + RS_TOKEN_KEYWORD (CONST, "const") \ + RS_TOKEN_KEYWORD (CONTINUE, "continue") \ + RS_TOKEN_KEYWORD (CRATE, "crate") \ + /* FIXME: Do we need to add $crate (DOLLAR_CRATE) as a reserved kw? */ \ + RS_TOKEN_KEYWORD (DO, "do") /* unused */ \ + RS_TOKEN_KEYWORD (DYN, "dyn") \ + RS_TOKEN_KEYWORD (ELSE, "else") \ + RS_TOKEN_KEYWORD (ENUM_TOK, "enum") \ + RS_TOKEN_KEYWORD (EXTERN_TOK, "extern") \ + RS_TOKEN_KEYWORD (FALSE_LITERAL, "false") \ + RS_TOKEN_KEYWORD (FINAL_TOK, "final") /* unused */ \ + RS_TOKEN_KEYWORD (FN_TOK, "fn") \ + RS_TOKEN_KEYWORD (FOR, "for") \ + RS_TOKEN_KEYWORD (IF, "if") \ + RS_TOKEN_KEYWORD (IMPL, "impl") \ + RS_TOKEN_KEYWORD (IN, "in") \ + RS_TOKEN_KEYWORD (LET, "let") \ + RS_TOKEN_KEYWORD (LOOP, "loop") \ + RS_TOKEN_KEYWORD (MACRO, "macro") /* unused */ \ + RS_TOKEN_KEYWORD (MATCH_TOK, "match") \ + RS_TOKEN_KEYWORD (MOD, "mod") \ + RS_TOKEN_KEYWORD (MOVE, "move") \ + RS_TOKEN_KEYWORD (MUT, "mut") \ + RS_TOKEN_KEYWORD (OVERRIDE_TOK, "override") /* unused */ \ + RS_TOKEN_KEYWORD (PRIV, "priv") /* unused */ \ + RS_TOKEN_KEYWORD (PUB, "pub") \ + RS_TOKEN_KEYWORD (REF, "ref") \ + RS_TOKEN_KEYWORD (RETURN_TOK, "return") \ + RS_TOKEN_KEYWORD (SELF_ALIAS, \ + "Self") /* mrustc does not treat this as a reserved word*/ \ + RS_TOKEN_KEYWORD (SELF, "self") \ + RS_TOKEN_KEYWORD (STATIC_TOK, "static") \ + RS_TOKEN_KEYWORD (STRUCT_TOK, "struct") \ + RS_TOKEN_KEYWORD (SUPER, "super") \ + RS_TOKEN_KEYWORD (TRAIT, "trait") \ + RS_TOKEN_KEYWORD (TRUE_LITERAL, "true") \ + RS_TOKEN_KEYWORD (TRY, "try") /* unused */ \ + RS_TOKEN_KEYWORD (TYPE, "type") \ + RS_TOKEN_KEYWORD (TYPEOF, "typeof") /* unused */ \ + RS_TOKEN_KEYWORD (UNSAFE, "unsafe") \ + RS_TOKEN_KEYWORD (UNSIZED, "unsized") /* unused */ \ + RS_TOKEN_KEYWORD (USE, "use") \ + RS_TOKEN_KEYWORD (VIRTUAL, "virtual") /* unused */ \ + RS_TOKEN_KEYWORD (WHERE, "where") \ + RS_TOKEN_KEYWORD (WHILE, "while") \ + RS_TOKEN_KEYWORD (YIELD, "yield") /* unused */ \ + \ + RS_TOKEN (LAST_TOKEN, "") + +// Contains all token types. Crappy implementation via x-macros. +enum TokenId +{ +#define RS_TOKEN(name, _) name, +#define RS_TOKEN_KEYWORD(x, y) RS_TOKEN (x, y) + RS_TOKEN_LIST +#undef RS_TOKEN_KEYWORD +#undef RS_TOKEN +}; + +// dodgy "TokenPtr" declaration with Token forward declaration +class Token; +// A smart pointer (shared_ptr) to Token. +typedef std::shared_ptr TokenPtr; +// A smart pointer (shared_ptr) to a constant Token. +typedef std::shared_ptr const_TokenPtr; + +// Hackily defined way to get token description for enum value using x-macros +const char * +get_token_description (TokenId id); +/* Hackily defined way to get token description as a string for enum value using + * x-macros */ +const char * +token_id_to_str (TokenId id); +// Get type hint description as a string. +const char * +get_type_hint_string (PrimitiveCoreType type); + +// Represents a single token. Create using factory static methods. +class Token +{ +private: + // Token kind. + TokenId token_id; + // Token location. + Location locus; + // Associated text (if any) of token. + std::unique_ptr str; + // TODO: maybe remove issues and just store std::string as value? + /* Type hint for token based on lexer data (e.g. type suffix). Does not exist + * for most tokens. */ + PrimitiveCoreType type_hint; + + // Token constructor from token id and location. Has a null string. + Token (TokenId token_id, Location location) + : token_id (token_id), locus (location), str (nullptr), + type_hint (CORETYPE_UNKNOWN) + {} + + // Token constructor from token id, location, and a string. + Token (TokenId token_id, Location location, std::string &¶mStr) + : token_id (token_id), locus (location), + str (new std::string (std::move (paramStr))), type_hint (CORETYPE_UNKNOWN) + {} + + // Token constructor from token id, location, and a char. + Token (TokenId token_id, Location location, char paramChar) + : token_id (token_id), locus (location), + str (new std::string (1, paramChar)), type_hint (CORETYPE_UNKNOWN) + {} + + // Token constructor from token id, location, and a "codepoint". + Token (TokenId token_id, Location location, Codepoint paramCodepoint) + : token_id (token_id), locus (location), + str (new std::string (paramCodepoint.as_string ())), + type_hint (CORETYPE_UNKNOWN) + {} + + // Token constructor from token id, location, a string, and type hint. + Token (TokenId token_id, Location location, std::string &¶mStr, + PrimitiveCoreType parType) + : token_id (token_id), locus (location), + str (new std::string (std::move (paramStr))), type_hint (parType) + {} + +public: + // No default constructor. + Token () = delete; + // Do not copy/assign tokens. + Token (const Token &) = delete; + Token &operator= (const Token &) = delete; + + // Allow moving tokens. + Token (Token &&other) = default; + Token &operator= (Token &&other) = default; + + ~Token () = default; + + /* TODO: make_shared (which saves a heap allocation) does not work with the + * private constructor */ + + // Makes and returns a new TokenPtr (with null string). + static TokenPtr make (TokenId token_id, Location locus) + { + // return std::make_shared (token_id, locus); + return TokenPtr (new Token (token_id, locus)); + } + + // Makes and returns a new TokenPtr of type IDENTIFIER. + static TokenPtr make_identifier (Location locus, std::string &&str) + { + // return std::make_shared (IDENTIFIER, locus, str); + return TokenPtr (new Token (IDENTIFIER, locus, std::move (str))); + } + + // Makes and returns a new TokenPtr of type INT_LITERAL. + static TokenPtr make_int (Location locus, std::string &&str, + PrimitiveCoreType type_hint = CORETYPE_UNKNOWN) + { + // return std::make_shared (INT_LITERAL, locus, str, type_hint); + return TokenPtr ( + new Token (INT_LITERAL, locus, std::move (str), type_hint)); + } + + // Makes and returns a new TokenPtr of type FLOAT_LITERAL. + static TokenPtr make_float (Location locus, std::string &&str, + PrimitiveCoreType type_hint = CORETYPE_UNKNOWN) + { + // return std::make_shared (FLOAT_LITERAL, locus, str, type_hint); + return TokenPtr ( + new Token (FLOAT_LITERAL, locus, std::move (str), type_hint)); + } + + // Makes and returns a new TokenPtr of type STRING_LITERAL. + static TokenPtr make_string (Location locus, std::string &&str) + { + // return std::make_shared (STRING_LITERAL, locus, str, + // CORETYPE_STR); + return TokenPtr ( + new Token (STRING_LITERAL, locus, std::move (str), CORETYPE_STR)); + } + + // Makes and returns a new TokenPtr of type CHAR_LITERAL. + static TokenPtr make_char (Location locus, Codepoint char_lit) + { + // return std::make_shared (CHAR_LITERAL, locus, char_lit); + return TokenPtr (new Token (CHAR_LITERAL, locus, char_lit)); + } + + // Makes and returns a new TokenPtr of type BYTE_CHAR_LITERAL. + static TokenPtr make_byte_char (Location locus, char byte_char) + { + // return std::make_shared (BYTE_CHAR_LITERAL, locus, byte_char); + return TokenPtr (new Token (BYTE_CHAR_LITERAL, locus, byte_char)); + } + + // Makes and returns a new TokenPtr of type BYTE_STRING_LITERAL (fix). + static TokenPtr make_byte_string (Location locus, std::string &&str) + { + // return std::make_shared (BYTE_STRING_LITERAL, locus, str); + return TokenPtr (new Token (BYTE_STRING_LITERAL, locus, std::move (str))); + } + + // Makes and returns a new TokenPtr of type INNER_DOC_COMMENT. + static TokenPtr make_inner_doc_comment (Location locus, std::string &&str) + { + return TokenPtr (new Token (INNER_DOC_COMMENT, locus, std::move (str))); + } + + // Makes and returns a new TokenPtr of type OUTER_DOC_COMMENT. + static TokenPtr make_outer_doc_comment (Location locus, std::string &&str) + { + return TokenPtr (new Token (OUTER_DOC_COMMENT, locus, std::move (str))); + } + + // Makes and returns a new TokenPtr of type LIFETIME. + static TokenPtr make_lifetime (Location locus, std::string &&str) + { + // return std::make_shared (LIFETIME, locus, str); + return TokenPtr (new Token (LIFETIME, locus, std::move (str))); + } + + // Gets id of the token. + TokenId get_id () const { return token_id; } + + // Gets location of the token. + Location get_locus () const { return locus; } + + // Gets string description of the token. + const std::string & + get_str () const; /*{ +// FIXME: put in header again when fix null problem +//gcc_assert(str != nullptr); +if (str == nullptr) { +error_at(get_locus(), "attempted to get string for '%s', which has no string. +returning empty string instead.", get_token_description()); return ""; +} +return *str; +}*/ + + // Gets token's type hint info. + PrimitiveCoreType get_type_hint () const + { + return type_hint == CORETYPE_PURE_DECIMAL ? CORETYPE_UNKNOWN : type_hint; + } + + // diagnostics (error reporting) + const char *get_token_description () const + { + return Rust::get_token_description (token_id); + } + + // debugging + const char *token_id_to_str () const + { + return Rust::token_id_to_str (token_id); + } + + // debugging + const char *get_type_hint_str () const; + + /* Returns whether the token is a literal of any type (int, float, char, + * string, byte char, byte string). */ + bool is_literal () const + { + switch (token_id) + { + case INT_LITERAL: + case FLOAT_LITERAL: + case CHAR_LITERAL: + case STRING_LITERAL: + case BYTE_CHAR_LITERAL: + case BYTE_STRING_LITERAL: + return true; + default: + return false; + } + } + + /* Returns whether the token actually has a string (regardless of whether it + * should or not). */ + bool has_str () const { return str != nullptr; } + + // Returns whether the token should have a string. + bool should_have_str () const + { + return is_literal () || token_id == IDENTIFIER || token_id == LIFETIME; + } + + // Returns whether the token is a pure decimal int literal + bool is_pure_decimal () const { return type_hint == CORETYPE_PURE_DECIMAL; } +}; +} // namespace Rust + +#endif diff --git a/gcc/rust/rust-buffered-queue.h b/gcc/rust/rust-buffered-queue.h new file mode 100644 index 00000000000..afcc4670cac --- /dev/null +++ b/gcc/rust/rust-buffered-queue.h @@ -0,0 +1,204 @@ +// 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_BUFFERED_QUEUE_H +#define RUST_BUFFERED_QUEUE_H + +#include "rust-system.h" + +namespace Rust { +/* Buffered queue implementation. Items are of type T, queue source is of type + * Source. Note that this is owning of the source. */ +template class buffered_queue +{ +public: + // Construct empty queue from Source src. + buffered_queue (Source src) : source (src), start (0), end (0), buffer () {} + + /* disable copying (since source is probably non-copyable) + * TODO is this actually a good idea? If source is non-copyable, it would + * just delete the copy constructor anyway.*/ + buffered_queue (const buffered_queue &other) = delete; + buffered_queue &operator= (const buffered_queue &other) = delete; + + // enable moving + buffered_queue (buffered_queue &&other) = default; + buffered_queue &operator= (buffered_queue &&other) = default; + + // Returns token at position start + n (i.e. n tokens ahead). + T peek (int n) + { + // n should not be behind + rust_assert (n >= 0); + + int num_queued_items = end - start; + int num_items_required = n + 1; + + // if required items go past end of queue, add them to queue + if (num_items_required > num_queued_items) + { + int num_items_to_read = num_items_required - num_queued_items; + + /* if queue length + extra items is larger than buffer size, expand + * buffer */ + if (end + num_items_to_read > (int) buffer.size ()) + { + // Resize the buffer by 1.5x + int new_size = (buffer.size () + num_items_to_read); + new_size += (new_size >> 1); + + // old method: + /* + // create new queue buffer with new size + std::vector new_queue (new_size); + std::copy (buffer.begin () + start, buffer.begin () + end, + new_queue.begin ()); + start = 0; + end = num_queued_items; + // TODO: would move be better here? optimisation for move with + // shared pointer? + + // swap member buffer and new queue buffer + std::swap (buffer, new_queue); + */ + + // TODO: determine overhead of this approach vs copy. Should be + // lower. + std::vector new_queue; + new_queue.reserve (new_size); + new_queue.insert (new_queue.begin (), + std::make_move_iterator (buffer.begin () + start), + std::make_move_iterator (buffer.begin () + end)); + start = 0; + end = num_queued_items; + // fill up rest of vector with junk so that indexing can work + new_queue.insert (new_queue.begin () + end, + new_size - new_queue.size (), T ()); + + buffer = std::move (new_queue); + /* this should be best method - std::move(range) would have + * allocation problems; initial construction would require + * reallocation upon resizing */ + + // validate that buffer is large enough now + rust_assert (end + num_items_to_read <= (int) buffer.size ()); + } + + /* iterate through buffer and invoke operator () on source on values + * past original end */ + for (int i = 0; i < num_items_to_read; i++) + buffer[end + i] = source.next (); + + // move end based on additional items added + end += num_items_to_read; + } + + rust_assert (0 <= start); + rust_assert (start <= end); + rust_assert (end <= (int) buffer.size ()); + + rust_assert (start + n < end); + + // return value at start + n in buffer + return buffer[start + n]; + } + + /* TODO: add faster peek current token to remove overhead of conditional + * branches? */ + + // Advances start by n + 1. + void skip (int n) + { + // Call peek to ensure requested n is actually in queue. + peek (n); + + // Clear queue values from start to n (inclusive). + for (int i = 0; i < (n + 1); i++) + buffer[start + i] = T (); + + // Move start forward by n + 1. + start += (n + 1); + + // Ensure start is not impossible somehow + rust_assert (0 <= start); + rust_assert (start <= end); + + // Compact buffer if empty + if (start == end) + start = end = 0; + } + + /* Inserts element at front of vector. Really dirty hack with terrible + * performance, only use when really needed. */ + void insert_at_front (T elem_to_insert) + { + // TODO: test as this may not work properly + + // Insert actual element in buffer at start. + buffer.insert (buffer.begin (), elem_to_insert); + + /* Increase the end number since added element means all others have shifted + * one along */ + end++; + } + + // Insert at arbitrary position (attempt) + void insert (int index, T elem_to_insert) + { + // TODO: test as this may not work properly + + // n should not be behind + rust_assert (index >= 0); + + // call peek to ensure that the items behind this (at least) are in queue + if (index >= 1) + peek (index - 1); + else + peek (index); + + buffer.insert (buffer.begin () + start + index, std::move (elem_to_insert)); + + end++; + } + + // Replaces the current value in the buffer. Total HACK. + void replace_current_value (T replacement) + { + // call peek to ensure value exists + peek (0); + + buffer[start] = std::move (replacement); + + // don't move start or end + } + +private: + // Source of tokens for queue. + Source source; + + // Begin of range in buffer, inclusive. + int start; + // End of range in buffer, exclusive. + int end; + + // Queue buffer. + std::vector buffer; +}; +} // namespace Rust + +#endif From patchwork Wed Aug 24 11:59:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56984 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 2EF8B3955C84 for ; Wed, 24 Aug 2022 12:02:51 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x431.google.com (mail-wr1-x431.google.com [IPv6:2a00:1450:4864:20::431]) by sourceware.org (Postfix) with ESMTPS id 2C189385022C; Wed, 24 Aug 2022 12:00:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 2C189385022C Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x431.google.com with SMTP id n7so20484431wrv.4; Wed, 24 Aug 2022 05:00:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=hus3mtKbo35A1J/fT6U8f2ROeBZZopTU7h4IRTZ33nI=; b=R3S3gvL2VzIxmwn+w0uuwS/WVxEcMiuotpY1OfcC77xWIoixXvBjOfudNDnrd27Cna 8RNvvG+tPVK8XRllZFiLMDWGNiS/g4B2VFB8Nt4qNARge6j8mHWn0PNTC7lqxXk51N4U hGuDS0jNNVIm6XR81td3O/WBU/Vxp/rFZD8ArHKfAWP7PQuN5LO40EoQWAr0h5oerB0m fjWvz299MIyhIhzlWsahG+TCkTcA+ccrc6xdjq/C4hyqzyDvaVyQMF76ztHuY2LyAN1d LeKQ1/Yx7BbyMr0jjwxzmMXWpgFn2CdJP9oN6uLk2lWPAyFmKaqWxmwMgN/SW2oYQTaN UKvA== 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; bh=hus3mtKbo35A1J/fT6U8f2ROeBZZopTU7h4IRTZ33nI=; b=2P7Rz6ZdflZvZx0EZPzx3Zw30c2QiYH7n2lxXdIiR+YJwpBFvg91Kh5TdjI0RVo8qE 1r0SQichXEY+YlLfh7XbLRcUutcreHr0PCrcns8T7YhOM9Qy6Z3H8H2P/HVsSSe2q2/D qsBpWkmiG1i0wEQh4tp0hbR/jSduAFFN7f1rN1/1Z6qt2BmqustclEBg7o4U6EL9sZ5Z ac1b8+0AfyI8WJwz3AzUPsDnQdRjeJYO1HWR0VJxolBmCdtl6/NXdxiaBlD5a+/dOCYK /obEQ1wRwd+18J8TfyvEAsMkRE5GXw1HVxgk1NGaDwyMEbc7Cj/Pmf4iXYDe8DmMI6OS mC0A== X-Gm-Message-State: ACgBeo0kwSRwqEv5qqRFU/33DdBYeu0BEY4fcGf/r2uFG+ruIDosWR6x xOpGCd1OVNFNHa8DAzoi21JrlcNlLSs= X-Google-Smtp-Source: AA6agR5YPwm5v4Mx8rrdSOu3jjWmhAhBGUEq9+YIcR+LhES6/KAPifX3SX7BLFG1dT/tvBqoUyTIqw== X-Received: by 2002:a5d:61c7:0:b0:225:307b:b557 with SMTP id q7-20020a5d61c7000000b00225307bb557mr14965248wrv.402.1661342443070; Wed, 24 Aug 2022 05:00:43 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:42 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 11/37] gccrs: Add expansion pass for the Rust front-end Date: Wed, 24 Aug 2022 12:59:30 +0100 Message-Id: <20220824115956.737931-12-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: Arthur Cohen , The Other , gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Arthur Cohen Arthur TODO Co-authored-by: Philip Herron Co-authored-by: The Other --- gcc/rust/expand/rust-attribute-visitor.cc | 3445 ++++++++++++++++++ gcc/rust/expand/rust-attribute-visitor.h | 316 ++ gcc/rust/expand/rust-macro-builtins.cc | 484 +++ gcc/rust/expand/rust-macro-builtins.h | 107 + gcc/rust/expand/rust-macro-expand.cc | 1012 +++++ gcc/rust/expand/rust-macro-expand.h | 366 ++ gcc/rust/expand/rust-macro-invoc-lexer.cc | 29 + gcc/rust/expand/rust-macro-invoc-lexer.h | 64 + gcc/rust/expand/rust-macro-substitute-ctx.cc | 312 ++ gcc/rust/expand/rust-macro-substitute-ctx.h | 93 + 10 files changed, 6228 insertions(+) create mode 100644 gcc/rust/expand/rust-attribute-visitor.cc create mode 100644 gcc/rust/expand/rust-attribute-visitor.h create mode 100644 gcc/rust/expand/rust-macro-builtins.cc create mode 100644 gcc/rust/expand/rust-macro-builtins.h create mode 100644 gcc/rust/expand/rust-macro-expand.cc create mode 100644 gcc/rust/expand/rust-macro-expand.h create mode 100644 gcc/rust/expand/rust-macro-invoc-lexer.cc create mode 100644 gcc/rust/expand/rust-macro-invoc-lexer.h create mode 100644 gcc/rust/expand/rust-macro-substitute-ctx.cc create mode 100644 gcc/rust/expand/rust-macro-substitute-ctx.h diff --git a/gcc/rust/expand/rust-attribute-visitor.cc b/gcc/rust/expand/rust-attribute-visitor.cc new file mode 100644 index 00000000000..8016f9430eb --- /dev/null +++ b/gcc/rust/expand/rust-attribute-visitor.cc @@ -0,0 +1,3445 @@ +// 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 +// . + +#include "rust-attribute-visitor.h" +#include "rust-session-manager.h" + +namespace Rust { + +// Visitor used to expand attributes. +void +AttrVisitor::expand_struct_fields (std::vector &fields) +{ + for (auto it = fields.begin (); it != fields.end ();) + { + auto &field = *it; + + auto &field_attrs = field.get_outer_attrs (); + expander.expand_cfg_attrs (field_attrs); + if (expander.fails_cfg_with_expand (field_attrs)) + { + it = fields.erase (it); + continue; + } + + expander.push_context (MacroExpander::ContextType::TYPE); + + // expand sub-types of type, but can't strip type itself + auto &type = field.get_field_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), + "cannot strip type in this position"); + + expander.pop_context (); + + // if nothing else happens, increment + ++it; + } +} + +void +AttrVisitor::expand_tuple_fields (std::vector &fields) +{ + for (auto it = fields.begin (); it != fields.end ();) + { + auto &field = *it; + + auto &field_attrs = field.get_outer_attrs (); + expander.expand_cfg_attrs (field_attrs); + if (expander.fails_cfg_with_expand (field_attrs)) + { + it = fields.erase (it); + continue; + } + + // expand sub-types of type, but can't strip type itself + auto &type = field.get_field_type (); + type->accept_vis (*this); + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), + "cannot strip type in this position"); + + // if nothing else happens, increment + ++it; + } +} + +void +AttrVisitor::expand_function_params (std::vector ¶ms) +{ + expander.push_context (MacroExpander::ContextType::TYPE); + + for (auto it = params.begin (); it != params.end ();) + { + auto ¶m = *it; + + auto ¶m_attrs = param.get_outer_attrs (); + expander.expand_cfg_attrs (param_attrs); + if (expander.fails_cfg_with_expand (param_attrs)) + { + it = params.erase (it); + continue; + } + + // TODO: should an unwanted strip lead to break out of loop? + auto &pattern = param.get_pattern (); + pattern->accept_vis (*this); + if (pattern->is_marked_for_strip ()) + rust_error_at (pattern->get_locus (), + "cannot strip pattern in this position"); + + auto &type = param.get_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), + "cannot strip type in this position"); + + // increment + ++it; + } + + expander.pop_context (); +} + +void +AttrVisitor::expand_generic_args (AST::GenericArgs &args) +{ + // lifetime args can't be expanded + // FIXME: Can we have macro invocations for lifetimes? + + expander.push_context (MacroExpander::ContextType::TYPE); + + // expand type args - strip sub-types only + for (auto &arg : args.get_generic_args ()) + { + switch (arg.get_kind ()) + { + case AST::GenericArg::Kind::Type: { + auto &type = arg.get_type (); + type->accept_vis (*this); + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), + "cannot strip type in this position"); + break; + } + case AST::GenericArg::Kind::Const: { + auto &expr = arg.get_expression (); + expr->accept_vis (*this); + maybe_expand_expr (expr); + + if (expr->is_marked_for_strip ()) + rust_error_at (expr->get_locus (), + "cannot strip expression in this position"); + break; + } + default: + break; + // FIXME: Figure out what to do here if there is ambiguity. Since the + // resolver comes after the expansion, we need to figure out a way to + // strip ambiguous values here + // TODO: Arthur: Probably add a `mark_as_strip` method to `GenericArg` + // or something. This would clean up this whole thing + } + } + + expander.pop_context (); + + // FIXME: Can we have macro invocations in generic type bindings? + // expand binding args - strip sub-types only + for (auto &binding : args.get_binding_args ()) + { + auto &type = binding.get_type (); + type->accept_vis (*this); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), + "cannot strip type in this position"); + } +} + +void +AttrVisitor::expand_qualified_path_type (AST::QualifiedPathType &path_type) +{ + expander.push_context (MacroExpander::ContextType::TYPE); + + auto &type = path_type.get_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + expander.pop_context (); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), "cannot strip type in this position"); + + if (path_type.has_as_clause ()) + { + auto &type_path = path_type.get_as_type_path (); + visit (type_path); + if (type_path.is_marked_for_strip ()) + rust_error_at (type_path.get_locus (), + "cannot strip type path in this position"); + } +} + +void +AttrVisitor::AttrVisitor::expand_closure_params ( + std::vector ¶ms) +{ + for (auto it = params.begin (); it != params.end ();) + { + auto ¶m = *it; + + auto ¶m_attrs = param.get_outer_attrs (); + expander.expand_cfg_attrs (param_attrs); + if (expander.fails_cfg_with_expand (param_attrs)) + { + it = params.erase (it); + continue; + } + + auto &pattern = param.get_pattern (); + pattern->accept_vis (*this); + if (pattern->is_marked_for_strip ()) + rust_error_at (pattern->get_locus (), + "cannot strip pattern in this position"); + + if (param.has_type_given ()) + { + expander.push_context (MacroExpander::ContextType::TYPE); + auto &type = param.get_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), + "cannot strip type in this position"); + + expander.pop_context (); + } + + // increment if found nothing else so far + ++it; + } +} + +void +AttrVisitor::expand_self_param (AST::SelfParam &self_param) +{ + if (self_param.has_type ()) + { + expander.push_context (MacroExpander::ContextType::TYPE); + auto &type = self_param.get_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), + "cannot strip type in this position"); + + expander.pop_context (); + } + /* TODO: maybe check for invariants being violated - e.g. both type and + * lifetime? */ +} + +void +AttrVisitor::expand_where_clause (AST::WhereClause &where_clause) +{ + // items cannot be stripped conceptually, so just accept visitor + for (auto &item : where_clause.get_items ()) + item->accept_vis (*this); +} + +void +AttrVisitor::expand_trait_function_decl (AST::TraitFunctionDecl &decl) +{ + // just expand sub-stuff - can't actually strip generic params themselves + for (auto ¶m : decl.get_generic_params ()) + param->accept_vis (*this); + + /* strip function parameters if required - this is specifically + * allowed by spec */ + expand_function_params (decl.get_function_params ()); + + if (decl.has_return_type ()) + { + expander.push_context (MacroExpander::ContextType::TYPE); + + auto &return_type = decl.get_return_type (); + return_type->accept_vis (*this); + + maybe_expand_type (return_type); + + if (return_type->is_marked_for_strip ()) + rust_error_at (return_type->get_locus (), + "cannot strip type in this position"); + + expander.pop_context (); + } + + if (decl.has_where_clause ()) + expand_where_clause (decl.get_where_clause ()); +} + +void +AttrVisitor::expand_trait_method_decl (AST::TraitMethodDecl &decl) +{ + // just expand sub-stuff - can't actually strip generic params themselves + for (auto ¶m : decl.get_generic_params ()) + param->accept_vis (*this); + + /* assuming you can't strip self param - wouldn't be a method + * anymore. spec allows outer attrs on self param, but doesn't + * specify whether cfg is used. */ + expand_self_param (decl.get_self_param ()); + + /* strip function parameters if required - this is specifically + * allowed by spec */ + expand_function_params (decl.get_function_params ()); + + if (decl.has_return_type ()) + { + expander.push_context (MacroExpander::ContextType::TYPE); + + auto &return_type = decl.get_return_type (); + return_type->accept_vis (*this); + + maybe_expand_type (return_type); + + if (return_type->is_marked_for_strip ()) + rust_error_at (return_type->get_locus (), + "cannot strip type in this position"); + + expander.pop_context (); + } + + if (decl.has_where_clause ()) + expand_where_clause (decl.get_where_clause ()); +} + +void +AttrVisitor::visit (AST::Token &) +{ + // shouldn't require? +} +void +AttrVisitor::visit (AST::DelimTokenTree &) +{ + // shouldn't require? +} +void +AttrVisitor::visit (AST::AttrInputMetaItemContainer &) +{ + // shouldn't require? +} +void +AttrVisitor::visit (AST::IdentifierExpr &ident_expr) +{ + // strip test based on outer attrs + expander.expand_cfg_attrs (ident_expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (ident_expr.get_outer_attrs ())) + { + ident_expr.mark_for_strip (); + return; + } +} +void +AttrVisitor::visit (AST::Lifetime &) +{ + // shouldn't require? +} +void +AttrVisitor::visit (AST::LifetimeParam &) +{ + // supposedly does not require - cfg does nothing +} +void +AttrVisitor::visit (AST::ConstGenericParam &) +{ + // likewise +} + +void +AttrVisitor::visit (AST::MacroInvocation ¯o_invoc) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (macro_invoc.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (macro_invoc.get_outer_attrs ())) + { + macro_invoc.mark_for_strip (); + return; + } + + // can't strip simple path + + // I don't think any macro token trees can be stripped in any way + + // TODO: maybe have cfg! macro stripping behaviour here? + expander.expand_invoc (macro_invoc, macro_invoc.has_semicolon ()); +} + +void +AttrVisitor::visit (AST::PathInExpression &path) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (path.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (path.get_outer_attrs ())) + { + path.mark_for_strip (); + return; + } + + for (auto &segment : path.get_segments ()) + { + if (segment.has_generic_args ()) + expand_generic_args (segment.get_generic_args ()); + } +} +void +AttrVisitor::visit (AST::TypePathSegment &) +{ + // shouldn't require +} +void +AttrVisitor::visit (AST::TypePathSegmentGeneric &segment) +{ + // TODO: strip inside generic args + + if (!segment.has_generic_args ()) + return; + + expand_generic_args (segment.get_generic_args ()); +} +void +AttrVisitor::visit (AST::TypePathSegmentFunction &segment) +{ + auto &type_path_function = segment.get_type_path_function (); + + for (auto &type : type_path_function.get_params ()) + { + type->accept_vis (*this); + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), + "cannot strip type in this position"); + } + + if (type_path_function.has_return_type ()) + { + expander.push_context (MacroExpander::ContextType::TYPE); + + auto &return_type = type_path_function.get_return_type (); + return_type->accept_vis (*this); + + maybe_expand_type (return_type); + + if (return_type->is_marked_for_strip ()) + rust_error_at (return_type->get_locus (), + "cannot strip type in this position"); + + expander.pop_context (); + } +} +void +AttrVisitor::visit (AST::TypePath &path) +{ + // this shouldn't strip any segments, but can strip inside them + for (auto &segment : path.get_segments ()) + segment->accept_vis (*this); +} +void +AttrVisitor::visit (AST::QualifiedPathInExpression &path) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (path.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (path.get_outer_attrs ())) + { + path.mark_for_strip (); + return; + } + + expand_qualified_path_type (path.get_qualified_path_type ()); + + for (auto &segment : path.get_segments ()) + { + if (segment.has_generic_args ()) + expand_generic_args (segment.get_generic_args ()); + } +} +void +AttrVisitor::visit (AST::QualifiedPathInType &path) +{ + expand_qualified_path_type (path.get_qualified_path_type ()); + + // this shouldn't strip any segments, but can strip inside them + for (auto &segment : path.get_segments ()) + segment->accept_vis (*this); +} + +void +AttrVisitor::visit (AST::LiteralExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } +} +void +AttrVisitor::visit (AST::AttrInputLiteral &) +{ + // shouldn't require? +} +void +AttrVisitor::visit (AST::MetaItemLitExpr &) +{ + // shouldn't require? +} +void +AttrVisitor::visit (AST::MetaItemPathLit &) +{ + // shouldn't require? +} +void +AttrVisitor::visit (AST::BorrowExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* strip any internal sub-expressions - expression itself isn't + * allowed to have external attributes in this position so can't be + * stripped. */ + auto &borrowed_expr = expr.get_borrowed_expr (); + borrowed_expr->accept_vis (*this); + if (borrowed_expr->is_marked_for_strip ()) + rust_error_at (borrowed_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::DereferenceExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* strip any internal sub-expressions - expression itself isn't + * allowed to have external attributes in this position so can't be + * stripped. */ + auto &dereferenced_expr = expr.get_dereferenced_expr (); + dereferenced_expr->accept_vis (*this); + if (dereferenced_expr->is_marked_for_strip ()) + rust_error_at (dereferenced_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::ErrorPropagationExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* strip any internal sub-expressions - expression itself isn't + * allowed to have external attributes in this position so can't be + * stripped. */ + auto &propagating_expr = expr.get_propagating_expr (); + propagating_expr->accept_vis (*this); + if (propagating_expr->is_marked_for_strip ()) + rust_error_at (propagating_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::NegationExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* strip any internal sub-expressions - expression itself isn't + * allowed to have external attributes in this position so can't be + * stripped. */ + auto &negated_expr = expr.get_negated_expr (); + negated_expr->accept_vis (*this); + if (negated_expr->is_marked_for_strip ()) + rust_error_at (negated_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::ArithmeticOrLogicalExpr &expr) +{ + /* outer attributes never allowed before these. while cannot strip + * two direct descendant expressions, can strip ones below that */ + + /* should have no possibility for outer attrs as would be parsed + * with outer expr */ + auto &l_expr = expr.get_left_expr (); + l_expr->accept_vis (*this); + maybe_expand_expr (l_expr); + + /* should syntactically not have outer attributes, though this may + * not have worked in practice */ + auto &r_expr = expr.get_right_expr (); + r_expr->accept_vis (*this); + maybe_expand_expr (r_expr); + + // ensure that they are not marked for strip + if (expr.get_left_expr ()->is_marked_for_strip ()) + rust_error_at (expr.get_left_expr ()->get_locus (), + "cannot strip expression in this position - outer " + "attributes are never allowed " + "before binary op exprs"); + if (expr.get_right_expr ()->is_marked_for_strip ()) + rust_error_at (expr.get_right_expr ()->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::ComparisonExpr &expr) +{ + /* outer attributes never allowed before these. while cannot strip + * two direct descendant expressions, can strip ones below that */ + + /* should have no possibility for outer attrs as would be parsed + * with outer expr */ + auto &l_expr = expr.get_left_expr (); + l_expr->accept_vis (*this); + maybe_expand_expr (l_expr); + + /* should syntactically not have outer attributes, though this may + * not have worked in practice */ + auto &r_expr = expr.get_right_expr (); + r_expr->accept_vis (*this); + maybe_expand_expr (r_expr); + + // ensure that they are not marked for strip + if (expr.get_left_expr ()->is_marked_for_strip ()) + rust_error_at (expr.get_left_expr ()->get_locus (), + "cannot strip expression in this position - outer " + "attributes are never allowed " + "before binary op exprs"); + if (expr.get_right_expr ()->is_marked_for_strip ()) + rust_error_at (expr.get_right_expr ()->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::LazyBooleanExpr &expr) +{ + /* outer attributes never allowed before these. while cannot strip + * two direct descendant expressions, can strip ones below that */ + + /* should have no possibility for outer attrs as would be parsed + * with outer expr */ + auto &l_expr = expr.get_left_expr (); + l_expr->accept_vis (*this); + maybe_expand_expr (l_expr); + + /* should syntactically not have outer attributes, though this may + * not have worked in practice */ + auto &r_expr = expr.get_right_expr (); + r_expr->accept_vis (*this); + maybe_expand_expr (r_expr); + + // ensure that they are not marked for strip + if (expr.get_left_expr ()->is_marked_for_strip ()) + rust_error_at (expr.get_left_expr ()->get_locus (), + "cannot strip expression in this position - outer " + "attributes are never allowed " + "before binary op exprs"); + if (expr.get_right_expr ()->is_marked_for_strip ()) + rust_error_at (expr.get_right_expr ()->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::TypeCastExpr &expr) +{ + /* outer attributes never allowed before these. while cannot strip + * direct descendant expression, can strip ones below that */ + + auto &casted_expr = expr.get_casted_expr (); + /* should have no possibility for outer attrs as would be parsed + * with outer expr */ + casted_expr->accept_vis (*this); + + // ensure that they are not marked for strip + if (casted_expr->is_marked_for_strip ()) + rust_error_at (casted_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes are never allowed before cast exprs"); + + // TODO: strip sub-types of type + auto &type = expr.get_type_to_cast_to (); + type->accept_vis (*this); + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), "cannot strip type in this position"); +} +void +AttrVisitor::visit (AST::AssignmentExpr &expr) +{ + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* should have no possibility for outer attrs as would be parsed + * with outer expr */ + auto &l_expr = expr.get_left_expr (); + l_expr->accept_vis (*this); + maybe_expand_expr (l_expr); + + /* should syntactically not have outer attributes, though this may + * not have worked in practice */ + auto &r_expr = expr.get_right_expr (); + r_expr->accept_vis (*this); + maybe_expand_expr (r_expr); + + // ensure that they are not marked for strip + if (expr.get_left_expr ()->is_marked_for_strip ()) + rust_error_at (expr.get_left_expr ()->get_locus (), + "cannot strip expression in this position - outer " + "attributes are never allowed " + "before binary op exprs"); + if (expr.get_right_expr ()->is_marked_for_strip ()) + rust_error_at (expr.get_right_expr ()->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::CompoundAssignmentExpr &expr) +{ + /* outer attributes never allowed before these. while cannot strip + * two direct descendant expressions, can strip ones below that */ + + /* should have no possibility for outer attrs as would be parsed + * with outer expr */ + auto &l_expr = expr.get_left_expr (); + l_expr->accept_vis (*this); + maybe_expand_expr (l_expr); + + /* should syntactically not have outer attributes, though this may + * not have worked in practice */ + auto &r_expr = expr.get_right_expr (); + r_expr->accept_vis (*this); + maybe_expand_expr (r_expr); + + // ensure that they are not marked for strip + if (expr.get_left_expr ()->is_marked_for_strip ()) + rust_error_at (expr.get_left_expr ()->get_locus (), + "cannot strip expression in this position - outer " + "attributes are never allowed " + "before binary op exprs"); + if (expr.get_right_expr ()->is_marked_for_strip ()) + rust_error_at (expr.get_right_expr ()->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::GroupedExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* strip test based on inner attrs - spec says these are inner + * attributes, not outer attributes of inner expr */ + expander.expand_cfg_attrs (expr.get_inner_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_inner_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* strip any internal sub-expressions - expression itself isn't + * allowed to have external attributes in this position so can't be + * stripped. */ + auto &inner_expr = expr.get_expr_in_parens (); + inner_expr->accept_vis (*this); + if (inner_expr->is_marked_for_strip ()) + rust_error_at (inner_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::ArrayElemsValues &elems) +{ + /* apparently outer attributes are allowed in "elements of array + * expressions" according to spec */ + expand_pointer_allow_strip (elems.get_values ()); +} +void +AttrVisitor::visit (AST::ArrayElemsCopied &elems) +{ + /* apparently outer attributes are allowed in "elements of array + * expressions" according to spec. on the other hand, it would not + * make conceptual sense to be able to remove either expression. As + * such, not implementing. TODO clear up the ambiguity here */ + + // only intend stripping for internal sub-expressions + auto &copied_expr = elems.get_elem_to_copy (); + copied_expr->accept_vis (*this); + if (copied_expr->is_marked_for_strip ()) + rust_error_at (copied_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + auto ©_count = elems.get_num_copies (); + copy_count->accept_vis (*this); + if (copy_count->is_marked_for_strip ()) + rust_error_at (copy_count->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::ArrayExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* strip test based on inner attrs - spec says there are separate + * inner attributes, not just outer attributes of inner exprs */ + expander.expand_cfg_attrs (expr.get_inner_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_inner_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* assuming you can't strip away the ArrayElems type, but can strip + * internal expressions and whatever */ + expr.get_array_elems ()->accept_vis (*this); +} +void +AttrVisitor::visit (AST::ArrayIndexExpr &expr) +{ + /* it is unclear whether outer attributes are supposed to be + * allowed, but conceptually it wouldn't make much sense, but + * having expansion code anyway. TODO */ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* strip any internal sub-expressions - expression itself isn't + * allowed to have external attributes in this position so can't be + * stripped. */ + auto &array_expr = expr.get_array_expr (); + array_expr->accept_vis (*this); + if (array_expr->is_marked_for_strip ()) + rust_error_at (array_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + auto &index_expr = expr.get_index_expr (); + index_expr->accept_vis (*this); + if (index_expr->is_marked_for_strip ()) + rust_error_at (index_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::TupleExpr &expr) +{ + /* according to spec, outer attributes are allowed on "elements of + * tuple expressions" */ + + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* strip test based on inner attrs - spec says these are inner + * attributes, not outer attributes of inner expr */ + expander.expand_cfg_attrs (expr.get_inner_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_inner_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* apparently outer attributes are allowed in "elements of tuple + * expressions" according to spec */ + expand_pointer_allow_strip (expr.get_tuple_elems ()); +} +void +AttrVisitor::visit (AST::TupleIndexExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* wouldn't strip this directly (as outer attrs should be + * associated with this level), but any sub-expressions would be + * stripped. Thus, no need to erase when strip check called. */ + auto &tuple_expr = expr.get_tuple_expr (); + tuple_expr->accept_vis (*this); + if (tuple_expr->is_marked_for_strip ()) + rust_error_at (tuple_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::StructExprStruct &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* strip test based on inner attrs - spec says these are inner + * attributes, not outer attributes of inner expr */ + expander.expand_cfg_attrs (expr.get_inner_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_inner_attrs ())) + { + expr.mark_for_strip (); + return; + } + + // strip sub-exprs of path + auto &struct_name = expr.get_struct_name (); + visit (struct_name); + if (struct_name.is_marked_for_strip ()) + rust_error_at (struct_name.get_locus (), + "cannot strip path in this position"); +} +void +AttrVisitor::visit (AST::StructExprFieldIdentifier &) +{ + // as no attrs (at moment, at least), no stripping possible +} +void +AttrVisitor::visit (AST::StructExprFieldIdentifierValue &field) +{ + /* as no attrs possible (at moment, at least), only sub-expression + * stripping is possible */ + auto &value = field.get_value (); + value->accept_vis (*this); + if (value->is_marked_for_strip ()) + rust_error_at (value->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::StructExprFieldIndexValue &field) +{ + /* as no attrs possible (at moment, at least), only sub-expression + * stripping is possible */ + auto &value = field.get_value (); + value->accept_vis (*this); + if (value->is_marked_for_strip ()) + rust_error_at (value->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::StructExprStructFields &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* strip test based on inner attrs - spec says these are inner + * attributes, not outer attributes of inner expr */ + expander.expand_cfg_attrs (expr.get_inner_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_inner_attrs ())) + { + expr.mark_for_strip (); + return; + } + + // strip sub-exprs of path + auto &struct_name = expr.get_struct_name (); + visit (struct_name); + if (struct_name.is_marked_for_strip ()) + rust_error_at (struct_name.get_locus (), + "cannot strip path in this position"); + + /* spec does not specify whether expressions are allowed to be + * stripped at top level of struct fields, but I wouldn't think + * that they would be, so operating under the assumption that only + * sub-expressions can be stripped. */ + for (auto &field : expr.get_fields ()) + { + field->accept_vis (*this); + // shouldn't strip in this + } + + /* struct base presumably can't be stripped, as the '..' is before + * the expression. as such, can only strip sub-expressions. */ + if (expr.has_struct_base ()) + { + auto &base_struct_expr = expr.get_struct_base ().get_base_struct (); + base_struct_expr->accept_vis (*this); + if (base_struct_expr->is_marked_for_strip ()) + rust_error_at (base_struct_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + } +} +void +AttrVisitor::visit (AST::StructExprStructBase &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* strip test based on inner attrs - spec says these are inner + * attributes, not outer attributes of inner expr */ + expander.expand_cfg_attrs (expr.get_inner_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_inner_attrs ())) + { + expr.mark_for_strip (); + return; + } + + // strip sub-exprs of path + auto &struct_name = expr.get_struct_name (); + visit (struct_name); + if (struct_name.is_marked_for_strip ()) + rust_error_at (struct_name.get_locus (), + "cannot strip path in this position"); + + /* struct base presumably can't be stripped, as the '..' is before + * the expression. as such, can only strip sub-expressions. */ + rust_assert (!expr.get_struct_base ().is_invalid ()); + auto &base_struct_expr = expr.get_struct_base ().get_base_struct (); + base_struct_expr->accept_vis (*this); + if (base_struct_expr->is_marked_for_strip ()) + rust_error_at (base_struct_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::CallExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* should not be outer attrs on "function" expression - outer attrs + * should be associated with call expr as a whole. only sub-expr + * expansion is possible. */ + auto &function = expr.get_function_expr (); + function->accept_vis (*this); + if (function->is_marked_for_strip ()) + rust_error_at (function->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + /* spec says outer attributes are specifically allowed for elements + * of call expressions, so full stripping possible */ + // FIXME: Arthur: Figure out how to refactor this - This is similar to + // expanding items in the crate or stmts in blocks + expand_pointer_allow_strip (expr.get_params ()); + auto ¶ms = expr.get_params (); + for (auto it = params.begin (); it != params.end ();) + { + auto &stmt = *it; + + stmt->accept_vis (*this); + + auto final_fragment = expand_macro_fragment_recursive (); + if (final_fragment.should_expand ()) + { + // Remove the current expanded invocation + it = params.erase (it); + for (auto &node : final_fragment.get_nodes ()) + { + it = params.insert (it, node.take_expr ()); + it++; + } + } + else if (stmt->is_marked_for_strip ()) + it = params.erase (it); + else + it++; + } +} +void +AttrVisitor::visit (AST::MethodCallExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* should not be outer attrs on "receiver" expression - outer attrs + * should be associated with call expr as a whole. only sub-expr + * expansion is possible. */ + auto &receiver = expr.get_receiver_expr (); + receiver->accept_vis (*this); + if (receiver->is_marked_for_strip ()) + rust_error_at (receiver->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + auto &method_name = expr.get_method_name (); + if (method_name.has_generic_args ()) + expand_generic_args (method_name.get_generic_args ()); + + /* spec says outer attributes are specifically allowed for elements + * of method call expressions, so full stripping possible */ + expand_pointer_allow_strip (expr.get_params ()); +} +void +AttrVisitor::visit (AST::FieldAccessExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* should not be outer attrs on "receiver" expression - outer attrs + * should be associated with field expr as a whole. only sub-expr + * expansion is possible. */ + auto &receiver = expr.get_receiver_expr (); + receiver->accept_vis (*this); + if (receiver->is_marked_for_strip ()) + rust_error_at (receiver->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::ClosureExprInner &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* strip closure parameters if required - this is specifically + * allowed by spec */ + expand_closure_params (expr.get_params ()); + + // can't strip expression itself, but can strip sub-expressions + auto &definition_expr = expr.get_definition_expr (); + definition_expr->accept_vis (*this); + if (definition_expr->is_marked_for_strip ()) + rust_error_at (definition_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} + +void +AttrVisitor::visit (AST::BlockExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* strip test based on inner attrs - spec says there are inner + * attributes, not just outer attributes of inner stmts */ + expander.expand_cfg_attrs (expr.get_inner_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_inner_attrs ())) + { + expr.mark_for_strip (); + return; + } + + std::function (AST::SingleASTNode)> extractor + = [] (AST::SingleASTNode node) { return node.take_stmt (); }; + + expand_macro_children (MacroExpander::BLOCK, expr.get_statements (), + extractor); + + expander.push_context (MacroExpander::BLOCK); + + // strip tail expression if exists - can actually fully remove it + if (expr.has_tail_expr ()) + { + auto &tail_expr = expr.get_tail_expr (); + + tail_expr->accept_vis (*this); + maybe_expand_expr (tail_expr); + + if (tail_expr->is_marked_for_strip ()) + expr.strip_tail_expr (); + } + expander.pop_context (); +} + +void +AttrVisitor::visit (AST::ClosureExprInnerTyped &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* strip closure parameters if required - this is specifically + * allowed by spec */ + expand_closure_params (expr.get_params ()); + + expander.push_context (MacroExpander::ContextType::TYPE); + + // can't strip return type, but can strip sub-types + auto &type = expr.get_return_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), "cannot strip type in this position"); + + expander.pop_context (); + + // can't strip expression itself, but can strip sub-expressions + auto &definition_block = expr.get_definition_block (); + definition_block->accept_vis (*this); + if (definition_block->is_marked_for_strip ()) + rust_error_at (definition_block->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::ContinueExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } +} +void +AttrVisitor::visit (AST::BreakExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* spec does not say that you can have outer attributes on + * expression, so assuming you can't. stripping for sub-expressions + * is the only thing that can be done */ + if (expr.has_break_expr ()) + { + auto &break_expr = expr.get_break_expr (); + + break_expr->accept_vis (*this); + + if (break_expr->is_marked_for_strip ()) + rust_error_at (break_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + } +} +void +AttrVisitor::visit (AST::RangeFromToExpr &expr) +{ + /* outer attributes never allowed before these. while cannot strip + * two direct descendant expressions, can strip ones below that */ + + /* should have no possibility for outer attrs as would be parsed + * with outer expr */ + expr.get_from_expr ()->accept_vis (*this); + /* should syntactically not have outer attributes, though this may + * not have worked in practice */ + expr.get_to_expr ()->accept_vis (*this); + + // ensure that they are not marked for strip + if (expr.get_from_expr ()->is_marked_for_strip ()) + rust_error_at (expr.get_from_expr ()->get_locus (), + "cannot strip expression in this position - outer " + "attributes are never allowed " + "before range exprs"); + if (expr.get_to_expr ()->is_marked_for_strip ()) + rust_error_at (expr.get_to_expr ()->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::RangeFromExpr &expr) +{ + /* outer attributes never allowed before these. while cannot strip + * direct descendant expression, can strip ones below that */ + + /* should have no possibility for outer attrs as would be parsed + * with outer expr */ + auto &from_expr = expr.get_from_expr (); + + from_expr->accept_vis (*this); + + if (from_expr->is_marked_for_strip ()) + rust_error_at (from_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes are never allowed before range exprs"); +} +void +AttrVisitor::visit (AST::RangeToExpr &expr) +{ + /* outer attributes never allowed before these. while cannot strip + * direct descendant expression, can strip ones below that */ + + /* should syntactically not have outer attributes, though this may + * not have worked in practice */ + auto &to_expr = expr.get_to_expr (); + + to_expr->accept_vis (*this); + + if (to_expr->is_marked_for_strip ()) + rust_error_at (to_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::RangeFullExpr &) +{ + // outer attributes never allowed before these, so no stripping +} +void +AttrVisitor::visit (AST::RangeFromToInclExpr &expr) +{ + /* outer attributes never allowed before these. while cannot strip + * two direct descendant expressions, can strip ones below that */ + + /* should have no possibility for outer attrs as would be parsed + * with outer expr */ + expr.get_from_expr ()->accept_vis (*this); + /* should syntactically not have outer attributes, though this may + * not have worked in practice */ + expr.get_to_expr ()->accept_vis (*this); + + // ensure that they are not marked for strip + if (expr.get_from_expr ()->is_marked_for_strip ()) + rust_error_at (expr.get_from_expr ()->get_locus (), + "cannot strip expression in this position - outer " + "attributes are never allowed " + "before range exprs"); + if (expr.get_to_expr ()->is_marked_for_strip ()) + rust_error_at (expr.get_to_expr ()->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::RangeToInclExpr &expr) +{ + /* outer attributes never allowed before these. while cannot strip + * direct descendant expression, can strip ones below that */ + + /* should syntactically not have outer attributes, though this may + * not have worked in practice */ + auto &to_expr = expr.get_to_expr (); + + to_expr->accept_vis (*this); + + if (to_expr->is_marked_for_strip ()) + rust_error_at (to_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::ReturnExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* spec does not say that you can have outer attributes on + * expression, so assuming you can't. stripping for sub-expressions + * is the only thing that can be done */ + if (expr.has_returned_expr ()) + { + auto &returned_expr = expr.get_returned_expr (); + + returned_expr->accept_vis (*this); + + if (returned_expr->is_marked_for_strip ()) + rust_error_at (returned_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + } + /* TODO: conceptually, you would maybe be able to remove a returned + * expr - e.g. if you had conditional compilation returning void or + * returning a type. On the other hand, I think that function + * return type cannot be conditionally compiled, so I assumed you + * can't do this either. */ +} +void +AttrVisitor::visit (AST::UnsafeBlockExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + // can't strip block itself, but can strip sub-expressions + auto &block_expr = expr.get_block_expr (); + block_expr->accept_vis (*this); + if (block_expr->is_marked_for_strip ()) + rust_error_at (block_expr->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::LoopExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + // can't strip block itself, but can strip sub-expressions + auto &loop_block = expr.get_loop_block (); + loop_block->accept_vis (*this); + if (loop_block->is_marked_for_strip ()) + rust_error_at (loop_block->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::WhileLoopExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + // can't strip predicate expr itself, but can strip sub-expressions + auto &predicate_expr = expr.get_predicate_expr (); + predicate_expr->accept_vis (*this); + if (predicate_expr->is_marked_for_strip ()) + rust_error_at (predicate_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + // can't strip block itself, but can strip sub-expressions + auto &loop_block = expr.get_loop_block (); + loop_block->accept_vis (*this); + if (loop_block->is_marked_for_strip ()) + rust_error_at (loop_block->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::WhileLetLoopExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + for (auto &pattern : expr.get_patterns ()) + { + pattern->accept_vis (*this); + if (pattern->is_marked_for_strip ()) + rust_error_at (pattern->get_locus (), + "cannot strip pattern in this position"); + } + + // can't strip scrutinee expr itself, but can strip sub-expressions + auto &scrutinee_expr = expr.get_scrutinee_expr (); + scrutinee_expr->accept_vis (*this); + if (scrutinee_expr->is_marked_for_strip ()) + rust_error_at (scrutinee_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + // can't strip block itself, but can strip sub-expressions + auto &loop_block = expr.get_loop_block (); + loop_block->accept_vis (*this); + if (loop_block->is_marked_for_strip ()) + rust_error_at (loop_block->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::ForLoopExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + // strip sub-patterns of pattern + auto &pattern = expr.get_pattern (); + pattern->accept_vis (*this); + if (pattern->is_marked_for_strip ()) + rust_error_at (pattern->get_locus (), + "cannot strip pattern in this position"); + + // can't strip scrutinee expr itself, but can strip sub-expressions + auto &iterator_expr = expr.get_iterator_expr (); + iterator_expr->accept_vis (*this); + if (iterator_expr->is_marked_for_strip ()) + rust_error_at (iterator_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + // can't strip block itself, but can strip sub-expressions + auto &loop_block = expr.get_loop_block (); + loop_block->accept_vis (*this); + if (loop_block->is_marked_for_strip ()) + rust_error_at (loop_block->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::IfExpr &expr) +{ + // rust playground test shows that IfExpr does support outer attrs, at least + // when used as statement + + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + // can't strip condition expr itself, but can strip sub-expressions + auto &condition_expr = expr.get_condition_expr (); + condition_expr->accept_vis (*this); + maybe_expand_expr (condition_expr); + if (condition_expr->is_marked_for_strip ()) + rust_error_at (condition_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + // can't strip if block itself, but can strip sub-expressions + auto &if_block = expr.get_if_block (); + if_block->accept_vis (*this); + if (if_block->is_marked_for_strip ()) + rust_error_at (if_block->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::IfExprConseqElse &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + // can't strip condition expr itself, but can strip sub-expressions + auto &condition_expr = expr.get_condition_expr (); + condition_expr->accept_vis (*this); + maybe_expand_expr (condition_expr); + if (condition_expr->is_marked_for_strip ()) + rust_error_at (condition_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + // can't strip if block itself, but can strip sub-expressions + auto &if_block = expr.get_if_block (); + if_block->accept_vis (*this); + if (if_block->is_marked_for_strip ()) + rust_error_at (if_block->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); + + // can't strip else block itself, but can strip sub-expressions + auto &else_block = expr.get_else_block (); + else_block->accept_vis (*this); + if (else_block->is_marked_for_strip ()) + rust_error_at (else_block->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::IfExprConseqIf &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + // can't strip condition expr itself, but can strip sub-expressions + auto &condition_expr = expr.get_condition_expr (); + condition_expr->accept_vis (*this); + maybe_expand_expr (condition_expr); + if (condition_expr->is_marked_for_strip ()) + rust_error_at (condition_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + // can't strip if block itself, but can strip sub-expressions + auto &if_block = expr.get_if_block (); + if_block->accept_vis (*this); + if (if_block->is_marked_for_strip ()) + rust_error_at (if_block->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); + + // can't strip if expr itself, but can strip sub-expressions + auto &conseq_if_expr = expr.get_conseq_if_expr (); + conseq_if_expr->accept_vis (*this); + if (conseq_if_expr->is_marked_for_strip ()) + rust_error_at (conseq_if_expr->get_locus (), + "cannot strip consequent if expression in this " + "position - outer attributes not allowed"); +} +void +AttrVisitor::visit (AST::IfExprConseqIfLet &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + // can't strip condition expr itself, but can strip sub-expressions + auto &condition_expr = expr.get_condition_expr (); + condition_expr->accept_vis (*this); + maybe_expand_expr (condition_expr); + if (condition_expr->is_marked_for_strip ()) + rust_error_at (condition_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + // can't strip if block itself, but can strip sub-expressions + auto &if_block = expr.get_if_block (); + if_block->accept_vis (*this); + if (if_block->is_marked_for_strip ()) + rust_error_at (if_block->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); + + // can't strip if let expr itself, but can strip sub-expressions + auto &conseq_if_let_expr = expr.get_conseq_if_let_expr (); + conseq_if_let_expr->accept_vis (*this); + if (conseq_if_let_expr->is_marked_for_strip ()) + rust_error_at (conseq_if_let_expr->get_locus (), + "cannot strip consequent if let expression in this " + "position - outer attributes not " + "allowed"); +} +void +AttrVisitor::visit (AST::IfLetExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + for (auto &pattern : expr.get_patterns ()) + { + pattern->accept_vis (*this); + if (pattern->is_marked_for_strip ()) + rust_error_at (pattern->get_locus (), + "cannot strip pattern in this position"); + } + + // can't strip value expr itself, but can strip sub-expressions + auto &value_expr = expr.get_value_expr (); + value_expr->accept_vis (*this); + if (value_expr->is_marked_for_strip ()) + rust_error_at (value_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + // can't strip if block itself, but can strip sub-expressions + auto &if_block = expr.get_if_block (); + if_block->accept_vis (*this); + if (if_block->is_marked_for_strip ()) + rust_error_at (if_block->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::IfLetExprConseqElse &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + for (auto &pattern : expr.get_patterns ()) + { + pattern->accept_vis (*this); + if (pattern->is_marked_for_strip ()) + rust_error_at (pattern->get_locus (), + "cannot strip pattern in this position"); + } + + // can't strip value expr itself, but can strip sub-expressions + auto &value_expr = expr.get_value_expr (); + value_expr->accept_vis (*this); + if (value_expr->is_marked_for_strip ()) + rust_error_at (value_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + // can't strip if block itself, but can strip sub-expressions + auto &if_block = expr.get_if_block (); + if_block->accept_vis (*this); + if (if_block->is_marked_for_strip ()) + rust_error_at (if_block->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); + + // can't strip else block itself, but can strip sub-expressions + auto &else_block = expr.get_else_block (); + else_block->accept_vis (*this); + if (else_block->is_marked_for_strip ()) + rust_error_at (else_block->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::IfLetExprConseqIf &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + for (auto &pattern : expr.get_patterns ()) + { + pattern->accept_vis (*this); + if (pattern->is_marked_for_strip ()) + rust_error_at (pattern->get_locus (), + "cannot strip pattern in this position"); + } + + // can't strip value expr itself, but can strip sub-expressions + auto &value_expr = expr.get_value_expr (); + value_expr->accept_vis (*this); + if (value_expr->is_marked_for_strip ()) + rust_error_at (value_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + // can't strip if block itself, but can strip sub-expressions + auto &if_block = expr.get_if_block (); + if_block->accept_vis (*this); + if (if_block->is_marked_for_strip ()) + rust_error_at (if_block->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); + + // can't strip if expr itself, but can strip sub-expressions + auto &conseq_if_expr = expr.get_conseq_if_expr (); + conseq_if_expr->accept_vis (*this); + if (conseq_if_expr->is_marked_for_strip ()) + rust_error_at (conseq_if_expr->get_locus (), + "cannot strip consequent if expression in this " + "position - outer attributes not allowed"); +} +void +AttrVisitor::visit (AST::IfLetExprConseqIfLet &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + for (auto &pattern : expr.get_patterns ()) + { + pattern->accept_vis (*this); + if (pattern->is_marked_for_strip ()) + rust_error_at (pattern->get_locus (), + "cannot strip pattern in this position"); + } + + // can't strip value expr itself, but can strip sub-expressions + auto &value_expr = expr.get_value_expr (); + value_expr->accept_vis (*this); + if (value_expr->is_marked_for_strip ()) + rust_error_at (value_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + // can't strip if block itself, but can strip sub-expressions + auto &if_block = expr.get_if_block (); + if_block->accept_vis (*this); + if (if_block->is_marked_for_strip ()) + rust_error_at (if_block->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); + + // can't strip if let expr itself, but can strip sub-expressions + auto &conseq_if_let_expr = expr.get_conseq_if_let_expr (); + conseq_if_let_expr->accept_vis (*this); + if (conseq_if_let_expr->is_marked_for_strip ()) + rust_error_at (conseq_if_let_expr->get_locus (), + "cannot strip consequent if let expression in this " + "position - outer attributes not " + "allowed"); +} +void +AttrVisitor::visit (AST::MatchExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + // inner attr strip test + expander.expand_cfg_attrs (expr.get_inner_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_inner_attrs ())) + { + expr.mark_for_strip (); + return; + } + + // can't strip scrutinee expr itself, but can strip sub-expressions + auto &scrutinee_expr = expr.get_scrutinee_expr (); + scrutinee_expr->accept_vis (*this); + if (scrutinee_expr->is_marked_for_strip ()) + rust_error_at (scrutinee_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + // strip match cases + auto &match_cases = expr.get_match_cases (); + for (auto it = match_cases.begin (); it != match_cases.end ();) + { + auto &match_case = *it; + + // strip match case based on outer attributes in match arm + auto &match_arm = match_case.get_arm (); + expander.expand_cfg_attrs (match_arm.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (match_arm.get_outer_attrs ())) + { + // strip match case + it = match_cases.erase (it); + continue; + } + + for (auto &pattern : match_arm.get_patterns ()) + { + pattern->accept_vis (*this); + if (pattern->is_marked_for_strip ()) + rust_error_at (pattern->get_locus (), + "cannot strip pattern in this position"); + } + + /* assuming that guard expression cannot be stripped as + * strictly speaking you would have to strip the whole guard to + * make syntactical sense, which you can't do. as such, only + * strip sub-expressions */ + if (match_arm.has_match_arm_guard ()) + { + auto &guard_expr = match_arm.get_guard_expr (); + guard_expr->accept_vis (*this); + if (guard_expr->is_marked_for_strip ()) + rust_error_at (guard_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + } + + // strip sub-expressions from match cases + auto &case_expr = match_case.get_expr (); + case_expr->accept_vis (*this); + if (case_expr->is_marked_for_strip ()) + rust_error_at (case_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + // increment to next case if haven't continued + ++it; + } +} +void +AttrVisitor::visit (AST::AwaitExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + /* can't strip awaited expr itself, but can strip sub-expressions + * - this is because you can't have no expr to await */ + auto &awaited_expr = expr.get_awaited_expr (); + awaited_expr->accept_vis (*this); + if (awaited_expr->is_marked_for_strip ()) + rust_error_at (awaited_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::AsyncBlockExpr &expr) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (expr.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (expr.get_outer_attrs ())) + { + expr.mark_for_strip (); + return; + } + + // can't strip block itself, but can strip sub-expressions + auto &block_expr = expr.get_block_expr (); + block_expr->accept_vis (*this); + if (block_expr->is_marked_for_strip ()) + rust_error_at (block_expr->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); +} + +void +AttrVisitor::visit (AST::TypeParam ¶m) +{ + // outer attributes don't actually do anything, so ignore them + + if (param.has_type_param_bounds ()) + { + // don't strip directly, only components of bounds + for (auto &bound : param.get_type_param_bounds ()) + bound->accept_vis (*this); + } + + if (param.has_type ()) + { + expander.push_context (MacroExpander::ContextType::TYPE); + auto &type = param.get_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), + "cannot strip type in this position"); + + expander.pop_context (); + } +} +void +AttrVisitor::visit (AST::LifetimeWhereClauseItem &) +{ + // shouldn't require +} +void +AttrVisitor::visit (AST::TypeBoundWhereClauseItem &item) +{ + // for lifetimes shouldn't require + + expander.push_context (MacroExpander::ContextType::TYPE); + + auto &type = item.get_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), "cannot strip type in this position"); + + expander.pop_context (); + + // don't strip directly, only components of bounds + for (auto &bound : item.get_type_param_bounds ()) + bound->accept_vis (*this); +} +void +AttrVisitor::visit (AST::Method &method) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (method.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (method.get_outer_attrs ())) + { + method.mark_for_strip (); + return; + } + + // just expand sub-stuff - can't actually strip generic params themselves + for (auto ¶m : method.get_generic_params ()) + param->accept_vis (*this); + + /* assuming you can't strip self param - wouldn't be a method + * anymore. spec allows outer attrs on self param, but doesn't + * specify whether cfg is used. */ + expand_self_param (method.get_self_param ()); + + /* strip method parameters if required - this is specifically + * allowed by spec */ + expand_function_params (method.get_function_params ()); + + if (method.has_return_type ()) + { + expander.push_context (MacroExpander::ContextType::TYPE); + + auto &return_type = method.get_return_type (); + return_type->accept_vis (*this); + + maybe_expand_type (return_type); + + if (return_type->is_marked_for_strip ()) + rust_error_at (return_type->get_locus (), + "cannot strip type in this position"); + + expander.pop_context (); + } + + if (method.has_where_clause ()) + expand_where_clause (method.get_where_clause ()); + + /* body should always exist - if error state, should have returned + * before now */ + // can't strip block itself, but can strip sub-expressions + auto &block_expr = method.get_definition (); + block_expr->accept_vis (*this); + if (block_expr->is_marked_for_strip ()) + rust_error_at (block_expr->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::Module &module) +{ + // strip test based on outer attrs + expander.expand_cfg_attrs (module.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (module.get_outer_attrs ())) + { + module.mark_for_strip (); + return; + } + + // A loaded module might have inner attributes + if (module.get_kind () == AST::Module::ModuleKind::LOADED) + { + // strip test based on inner attrs + expander.expand_cfg_attrs (module.get_inner_attrs ()); + if (expander.fails_cfg_with_expand (module.get_inner_attrs ())) + { + module.mark_for_strip (); + return; + } + } + + // Parse the module's items if they haven't been expanded and the file + // should be parsed (i.e isn't hidden behind an untrue or impossible cfg + // directive) + if (!module.is_marked_for_strip () + && module.get_kind () == AST::Module::ModuleKind::UNLOADED) + { + module.load_items (); + } + + // strip items if required + expand_pointer_allow_strip (module.get_items ()); +} +void +AttrVisitor::visit (AST::ExternCrate &extern_crate) +{ + // strip test based on outer attrs + expander.expand_cfg_attrs (extern_crate.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (extern_crate.get_outer_attrs ())) + { + extern_crate.mark_for_strip (); + return; + } + + if (!extern_crate.references_self ()) + { + Session &session = Session::get_instance (); + session.load_extern_crate (extern_crate.get_referenced_crate (), + extern_crate.get_locus ()); + } +} +void +AttrVisitor::visit (AST::UseTreeGlob &) +{ + // shouldn't require? +} +void +AttrVisitor::visit (AST::UseTreeList &) +{ + // shouldn't require? +} +void +AttrVisitor::visit (AST::UseTreeRebind &) +{ + // shouldn't require? +} +void +AttrVisitor::visit (AST::UseDeclaration &use_decl) +{ + // strip test based on outer attrs + expander.expand_cfg_attrs (use_decl.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (use_decl.get_outer_attrs ())) + { + use_decl.mark_for_strip (); + return; + } +} +void +AttrVisitor::visit (AST::Function &function) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (function.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (function.get_outer_attrs ())) + { + function.mark_for_strip (); + return; + } + + // just expand sub-stuff - can't actually strip generic params themselves + for (auto ¶m : function.get_generic_params ()) + param->accept_vis (*this); + + /* strip function parameters if required - this is specifically + * allowed by spec */ + expand_function_params (function.get_function_params ()); + + if (function.has_return_type ()) + { + expander.push_context (MacroExpander::ContextType::TYPE); + + auto &return_type = function.get_return_type (); + return_type->accept_vis (*this); + + maybe_expand_type (return_type); + + if (return_type->is_marked_for_strip ()) + rust_error_at (return_type->get_locus (), + "cannot strip type in this position"); + + expander.pop_context (); + } + + if (function.has_where_clause ()) + expand_where_clause (function.get_where_clause ()); + + /* body should always exist - if error state, should have returned + * before now */ + // can't strip block itself, but can strip sub-expressions + auto &block_expr = function.get_definition (); + block_expr->accept_vis (*this); + if (block_expr->is_marked_for_strip ()) + rust_error_at (block_expr->get_locus (), + "cannot strip block expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::TypeAlias &type_alias) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (type_alias.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (type_alias.get_outer_attrs ())) + { + type_alias.mark_for_strip (); + return; + } + + // just expand sub-stuff - can't actually strip generic params themselves + for (auto ¶m : type_alias.get_generic_params ()) + param->accept_vis (*this); + + if (type_alias.has_where_clause ()) + expand_where_clause (type_alias.get_where_clause ()); + + auto &type = type_alias.get_type_aliased (); + type->accept_vis (*this); + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), "cannot strip type in this position"); +} +void +AttrVisitor::visit (AST::StructStruct &struct_item) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (struct_item.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (struct_item.get_outer_attrs ())) + { + struct_item.mark_for_strip (); + return; + } + + // just expand sub-stuff - can't actually strip generic params themselves + for (auto ¶m : struct_item.get_generic_params ()) + param->accept_vis (*this); + + if (struct_item.has_where_clause ()) + expand_where_clause (struct_item.get_where_clause ()); + + /* strip struct fields if required - this is presumably + * allowed by spec */ + expand_struct_fields (struct_item.get_fields ()); +} +void +AttrVisitor::visit (AST::TupleStruct &tuple_struct) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (tuple_struct.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (tuple_struct.get_outer_attrs ())) + { + tuple_struct.mark_for_strip (); + return; + } + + // just expand sub-stuff - can't actually strip generic params themselves + for (auto ¶m : tuple_struct.get_generic_params ()) + param->accept_vis (*this); + + /* strip struct fields if required - this is presumably + * allowed by spec */ + expand_tuple_fields (tuple_struct.get_fields ()); + + if (tuple_struct.has_where_clause ()) + expand_where_clause (tuple_struct.get_where_clause ()); +} +void +AttrVisitor::visit (AST::EnumItem &item) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (item.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (item.get_outer_attrs ())) + { + item.mark_for_strip (); + return; + } +} +void +AttrVisitor::visit (AST::EnumItemTuple &item) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (item.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (item.get_outer_attrs ())) + { + item.mark_for_strip (); + return; + } + + /* strip item fields if required - this is presumably + * allowed by spec */ + expand_tuple_fields (item.get_tuple_fields ()); +} +void +AttrVisitor::visit (AST::EnumItemStruct &item) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (item.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (item.get_outer_attrs ())) + { + item.mark_for_strip (); + return; + } + + /* strip item fields if required - this is presumably + * allowed by spec */ + expand_struct_fields (item.get_struct_fields ()); +} +void +AttrVisitor::visit (AST::EnumItemDiscriminant &item) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (item.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (item.get_outer_attrs ())) + { + item.mark_for_strip (); + return; + } + + /* strip any internal sub-expressions - expression itself isn't + * allowed to have external attributes in this position so can't be + * stripped. */ + auto &expr = item.get_expr (); + expr->accept_vis (*this); + if (expr->is_marked_for_strip ()) + rust_error_at (expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::Enum &enum_item) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (enum_item.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (enum_item.get_outer_attrs ())) + { + enum_item.mark_for_strip (); + return; + } + + // just expand sub-stuff - can't actually strip generic params themselves + for (auto ¶m : enum_item.get_generic_params ()) + param->accept_vis (*this); + + if (enum_item.has_where_clause ()) + expand_where_clause (enum_item.get_where_clause ()); + + /* strip enum fields if required - this is presumably + * allowed by spec */ + expand_pointer_allow_strip (enum_item.get_variants ()); +} +void +AttrVisitor::visit (AST::Union &union_item) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (union_item.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (union_item.get_outer_attrs ())) + { + union_item.mark_for_strip (); + return; + } + + // just expand sub-stuff - can't actually strip generic params themselves + for (auto ¶m : union_item.get_generic_params ()) + param->accept_vis (*this); + + if (union_item.has_where_clause ()) + expand_where_clause (union_item.get_where_clause ()); + + /* strip union fields if required - this is presumably + * allowed by spec */ + expand_struct_fields (union_item.get_variants ()); +} +void +AttrVisitor::visit (AST::ConstantItem &const_item) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (const_item.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (const_item.get_outer_attrs ())) + { + const_item.mark_for_strip (); + return; + } + + expander.push_context (MacroExpander::ContextType::TYPE); + + // strip any sub-types + auto &type = const_item.get_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), "cannot strip type in this position"); + + expander.pop_context (); + + /* strip any internal sub-expressions - expression itself isn't + * allowed to have external attributes in this position so can't be + * stripped. */ + auto &expr = const_item.get_expr (); + expr->accept_vis (*this); + if (expr->is_marked_for_strip ()) + rust_error_at (expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::StaticItem &static_item) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (static_item.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (static_item.get_outer_attrs ())) + { + static_item.mark_for_strip (); + return; + } + + expander.push_context (MacroExpander::ContextType::TYPE); + + // strip any sub-types + auto &type = static_item.get_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), "cannot strip type in this position"); + + expander.pop_context (); + + /* strip any internal sub-expressions - expression itself isn't + * allowed to have external attributes in this position so can't be + * stripped. */ + auto &expr = static_item.get_expr (); + expr->accept_vis (*this); + if (expr->is_marked_for_strip ()) + rust_error_at (expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); +} +void +AttrVisitor::visit (AST::TraitItemFunc &item) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (item.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (item.get_outer_attrs ())) + { + item.mark_for_strip (); + return; + } + + expand_trait_function_decl (item.get_trait_function_decl ()); + + if (item.has_definition ()) + { + /* strip any internal sub-expressions - expression itself isn't + * allowed to have external attributes in this position so can't be + * stripped. */ + auto &block = item.get_definition (); + block->accept_vis (*this); + if (block->is_marked_for_strip ()) + rust_error_at (block->get_locus (), + "cannot strip block expression in this " + "position - outer attributes not allowed"); + } +} +void +AttrVisitor::visit (AST::TraitItemMethod &item) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (item.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (item.get_outer_attrs ())) + { + item.mark_for_strip (); + return; + } + + expand_trait_method_decl (item.get_trait_method_decl ()); + + if (item.has_definition ()) + { + /* strip any internal sub-expressions - expression itself isn't + * allowed to have external attributes in this position so can't be + * stripped. */ + auto &block = item.get_definition (); + block->accept_vis (*this); + if (block->is_marked_for_strip ()) + rust_error_at (block->get_locus (), + "cannot strip block expression in this " + "position - outer attributes not allowed"); + } +} +void +AttrVisitor::visit (AST::TraitItemConst &item) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (item.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (item.get_outer_attrs ())) + { + item.mark_for_strip (); + return; + } + + expander.push_context (MacroExpander::ContextType::TYPE); + + // strip any sub-types + auto &type = item.get_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), "cannot strip type in this position"); + + expander.pop_context (); + + /* strip any internal sub-expressions - expression itself isn't + * allowed to have external attributes in this position so can't be + * stripped */ + if (item.has_expression ()) + { + auto &expr = item.get_expr (); + expr->accept_vis (*this); + if (expr->is_marked_for_strip ()) + rust_error_at (expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + } +} +void +AttrVisitor::visit (AST::TraitItemType &item) +{ + // initial test based on outer attrs + expander.expand_cfg_attrs (item.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (item.get_outer_attrs ())) + { + item.mark_for_strip (); + return; + } + + if (item.has_type_param_bounds ()) + { + // don't strip directly, only components of bounds + for (auto &bound : item.get_type_param_bounds ()) + bound->accept_vis (*this); + } +} +void +AttrVisitor::visit (AST::Trait &trait) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (trait.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (trait.get_outer_attrs ())) + { + trait.mark_for_strip (); + return; + } + + // strip test based on inner attrs + expander.expand_cfg_attrs (trait.get_inner_attrs ()); + if (expander.fails_cfg_with_expand (trait.get_inner_attrs ())) + { + trait.mark_for_strip (); + return; + } + + // just expand sub-stuff - can't actually strip generic params themselves + for (auto ¶m : trait.get_generic_params ()) + param->accept_vis (*this); + + if (trait.has_type_param_bounds ()) + { + // don't strip directly, only components of bounds + for (auto &bound : trait.get_type_param_bounds ()) + bound->accept_vis (*this); + } + + if (trait.has_where_clause ()) + expand_where_clause (trait.get_where_clause ()); + + std::function (AST::SingleASTNode)> extractor + = [] (AST::SingleASTNode node) { return node.take_trait_item (); }; + + expand_macro_children (MacroExpander::TRAIT, trait.get_trait_items (), + extractor); +} +void +AttrVisitor::visit (AST::InherentImpl &impl) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (impl.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (impl.get_outer_attrs ())) + { + impl.mark_for_strip (); + return; + } + + // strip test based on inner attrs + expander.expand_cfg_attrs (impl.get_inner_attrs ()); + if (expander.fails_cfg_with_expand (impl.get_inner_attrs ())) + { + impl.mark_for_strip (); + return; + } + + // just expand sub-stuff - can't actually strip generic params themselves + for (auto ¶m : impl.get_generic_params ()) + param->accept_vis (*this); + + expander.push_context (MacroExpander::ContextType::TYPE); + + auto &type = impl.get_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), "cannot strip type in this position"); + + expander.pop_context (); + + if (impl.has_where_clause ()) + expand_where_clause (impl.get_where_clause ()); + + std::function (AST::SingleASTNode)> + extractor = [] (AST::SingleASTNode node) { return node.take_impl_item (); }; + + expand_macro_children (MacroExpander::IMPL, impl.get_impl_items (), + extractor); +} +void +AttrVisitor::visit (AST::TraitImpl &impl) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (impl.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (impl.get_outer_attrs ())) + { + impl.mark_for_strip (); + return; + } + + // strip test based on inner attrs + expander.expand_cfg_attrs (impl.get_inner_attrs ()); + if (expander.fails_cfg_with_expand (impl.get_inner_attrs ())) + { + impl.mark_for_strip (); + return; + } + + // just expand sub-stuff - can't actually strip generic params themselves + for (auto ¶m : impl.get_generic_params ()) + param->accept_vis (*this); + + expander.push_context (MacroExpander::ContextType::TYPE); + + auto &type = impl.get_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), "cannot strip type in this position"); + + expander.pop_context (); + + auto &trait_path = impl.get_trait_path (); + visit (trait_path); + if (trait_path.is_marked_for_strip ()) + rust_error_at (trait_path.get_locus (), + "cannot strip typepath in this position"); + + if (impl.has_where_clause ()) + expand_where_clause (impl.get_where_clause ()); + + std::function (AST::SingleASTNode)> + extractor + = [] (AST::SingleASTNode node) { return node.take_trait_impl_item (); }; + + expand_macro_children (MacroExpander::TRAIT_IMPL, impl.get_impl_items (), + extractor); +} +void +AttrVisitor::visit (AST::ExternalStaticItem &item) +{ + // strip test based on outer attrs + expander.expand_cfg_attrs (item.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (item.get_outer_attrs ())) + { + item.mark_for_strip (); + return; + } + + expander.push_context (MacroExpander::ContextType::TYPE); + + auto &type = item.get_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), "cannot strip type in this position"); + + expander.pop_context (); +} +void +AttrVisitor::visit (AST::ExternalFunctionItem &item) +{ + // strip test based on outer attrs + expander.expand_cfg_attrs (item.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (item.get_outer_attrs ())) + { + item.mark_for_strip (); + return; + } + + // just expand sub-stuff - can't actually strip generic params themselves + for (auto ¶m : item.get_generic_params ()) + param->accept_vis (*this); + + /* strip function parameters if required - this is specifically + * allowed by spec */ + auto ¶ms = item.get_function_params (); + for (auto it = params.begin (); it != params.end ();) + { + auto ¶m = *it; + + auto ¶m_attrs = param.get_outer_attrs (); + expander.expand_cfg_attrs (param_attrs); + if (expander.fails_cfg_with_expand (param_attrs)) + { + it = params.erase (it); + continue; + } + + expander.push_context (MacroExpander::ContextType::TYPE); + + auto &type = param.get_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), + "cannot strip type in this position"); + + expander.pop_context (); + + // increment if nothing else happens + ++it; + } + /* NOTE: these are extern function params, which may have different + * rules and restrictions to "normal" function params. So expansion + * handled separately. */ + + /* TODO: assuming that variadic nature cannot be stripped. If this + * is not true, then have code here to do so. */ + + if (item.has_return_type ()) + { + expander.push_context (MacroExpander::ContextType::TYPE); + + auto &return_type = item.get_return_type (); + return_type->accept_vis (*this); + + maybe_expand_type (return_type); + + if (return_type->is_marked_for_strip ()) + rust_error_at (return_type->get_locus (), + "cannot strip type in this position"); + + expander.pop_context (); + } + + if (item.has_where_clause ()) + expand_where_clause (item.get_where_clause ()); +} + +void +AttrVisitor::visit (AST::ExternBlock &block) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (block.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (block.get_outer_attrs ())) + { + block.mark_for_strip (); + return; + } + + // strip test based on inner attrs + expander.expand_cfg_attrs (block.get_inner_attrs ()); + if (expander.fails_cfg_with_expand (block.get_inner_attrs ())) + { + block.mark_for_strip (); + return; + } + + std::function (AST::SingleASTNode)> + extractor + = [] (AST::SingleASTNode node) { return node.take_external_item (); }; + + expand_macro_children (MacroExpander::EXTERN, block.get_extern_items (), + extractor); +} + +// I don't think it would be possible to strip macros without expansion +void +AttrVisitor::visit (AST::MacroMatchFragment &) +{} +void +AttrVisitor::visit (AST::MacroMatchRepetition &) +{} +void +AttrVisitor::visit (AST::MacroMatcher &) +{} +void +AttrVisitor::visit (AST::MacroRulesDefinition &rules_def) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (rules_def.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (rules_def.get_outer_attrs ())) + { + rules_def.mark_for_strip (); + return; + } + + // I don't think any macro rules can be stripped in any way + + auto path = Resolver::CanonicalPath::new_seg (rules_def.get_node_id (), + rules_def.get_rule_name ()); + expander.resolver->get_macro_scope ().insert (path, rules_def.get_node_id (), + rules_def.get_locus ()); + expander.mappings->insert_macro_def (&rules_def); + rust_debug_loc (rules_def.get_locus (), "inserting macro def: [%s]", + path.get ().c_str ()); +} + +void +AttrVisitor::visit (AST::MetaItemPath &) +{} +void +AttrVisitor::visit (AST::MetaItemSeq &) +{} +void +AttrVisitor::visit (AST::MetaWord &) +{} +void +AttrVisitor::visit (AST::MetaNameValueStr &) +{} +void +AttrVisitor::visit (AST::MetaListPaths &) +{} +void +AttrVisitor::visit (AST::MetaListNameValueStr &) +{} + +void +AttrVisitor::visit (AST::LiteralPattern &) +{ + // not possible +} +void +AttrVisitor::visit (AST::IdentifierPattern &pattern) +{ + // can only strip sub-patterns of the inner pattern to bind + if (!pattern.has_pattern_to_bind ()) + return; + + auto &sub_pattern = pattern.get_pattern_to_bind (); + sub_pattern->accept_vis (*this); + if (sub_pattern->is_marked_for_strip ()) + rust_error_at (sub_pattern->get_locus (), + "cannot strip pattern in this position"); +} +void +AttrVisitor::visit (AST::WildcardPattern &) +{ + // not possible +} +void +AttrVisitor::visit (AST::RangePatternBoundLiteral &) +{ + // not possible +} +void +AttrVisitor::visit (AST::RangePatternBoundPath &bound) +{ + // can expand path, but not strip it directly + auto &path = bound.get_path (); + visit (path); + if (path.is_marked_for_strip ()) + rust_error_at (path.get_locus (), "cannot strip path in this position"); +} +void +AttrVisitor::visit (AST::RangePatternBoundQualPath &bound) +{ + // can expand path, but not strip it directly + auto &path = bound.get_qualified_path (); + visit (path); + if (path.is_marked_for_strip ()) + rust_error_at (path.get_locus (), "cannot strip path in this position"); +} +void +AttrVisitor::visit (AST::RangePattern &pattern) +{ + // should have no capability to strip lower or upper bounds, only expand + pattern.get_lower_bound ()->accept_vis (*this); + pattern.get_upper_bound ()->accept_vis (*this); +} +void +AttrVisitor::visit (AST::ReferencePattern &pattern) +{ + auto &sub_pattern = pattern.get_referenced_pattern (); + sub_pattern->accept_vis (*this); + if (sub_pattern->is_marked_for_strip ()) + rust_error_at (sub_pattern->get_locus (), + "cannot strip pattern in this position"); +} +void +AttrVisitor::visit (AST::StructPatternFieldTuplePat &field) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (field.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (field.get_outer_attrs ())) + { + field.mark_for_strip (); + return; + } + + // strip sub-patterns (can't strip top-level pattern) + auto &sub_pattern = field.get_index_pattern (); + sub_pattern->accept_vis (*this); + if (sub_pattern->is_marked_for_strip ()) + rust_error_at (sub_pattern->get_locus (), + "cannot strip pattern in this position"); +} +void +AttrVisitor::visit (AST::StructPatternFieldIdentPat &field) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (field.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (field.get_outer_attrs ())) + { + field.mark_for_strip (); + return; + } + + // strip sub-patterns (can't strip top-level pattern) + auto &sub_pattern = field.get_ident_pattern (); + sub_pattern->accept_vis (*this); + if (sub_pattern->is_marked_for_strip ()) + rust_error_at (sub_pattern->get_locus (), + "cannot strip pattern in this position"); +} +void +AttrVisitor::visit (AST::StructPatternFieldIdent &field) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (field.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (field.get_outer_attrs ())) + { + field.mark_for_strip (); + return; + } +} +void +AttrVisitor::visit (AST::StructPattern &pattern) +{ + // expand (but don't strip) path + auto &path = pattern.get_path (); + visit (path); + if (path.is_marked_for_strip ()) + rust_error_at (path.get_locus (), "cannot strip path in this position"); + + /* TODO: apparently struct pattern fields can have outer attrs. so can they + * be stripped? */ + if (!pattern.has_struct_pattern_elems ()) + return; + + auto &elems = pattern.get_struct_pattern_elems (); + + // assuming you can strip struct pattern fields + expand_pointer_allow_strip (elems.get_struct_pattern_fields ()); + + // assuming you can strip the ".." part + if (elems.has_etc ()) + { + expander.expand_cfg_attrs (elems.get_etc_outer_attrs ()); + if (expander.fails_cfg_with_expand (elems.get_etc_outer_attrs ())) + elems.strip_etc (); + } +} +void +AttrVisitor::visit (AST::TupleStructItemsNoRange &tuple_items) +{ + // can't strip individual patterns, only sub-patterns + for (auto &pattern : tuple_items.get_patterns ()) + { + pattern->accept_vis (*this); + + if (pattern->is_marked_for_strip ()) + rust_error_at (pattern->get_locus (), + "cannot strip pattern in this position"); + // TODO: quit stripping now? or keep going? + } +} +void +AttrVisitor::visit (AST::TupleStructItemsRange &tuple_items) +{ + // can't strip individual patterns, only sub-patterns + for (auto &lower_pattern : tuple_items.get_lower_patterns ()) + { + lower_pattern->accept_vis (*this); + + if (lower_pattern->is_marked_for_strip ()) + rust_error_at (lower_pattern->get_locus (), + "cannot strip pattern in this position"); + // TODO: quit stripping now? or keep going? + } + for (auto &upper_pattern : tuple_items.get_upper_patterns ()) + { + upper_pattern->accept_vis (*this); + + if (upper_pattern->is_marked_for_strip ()) + rust_error_at (upper_pattern->get_locus (), + "cannot strip pattern in this position"); + // TODO: quit stripping now? or keep going? + } +} +void +AttrVisitor::visit (AST::TupleStructPattern &pattern) +{ + // expand (but don't strip) path + auto &path = pattern.get_path (); + visit (path); + if (path.is_marked_for_strip ()) + rust_error_at (path.get_locus (), "cannot strip path in this position"); + + if (pattern.has_items ()) + pattern.get_items ()->accept_vis (*this); +} +void +AttrVisitor::visit (AST::TuplePatternItemsMultiple &tuple_items) +{ + // can't strip individual patterns, only sub-patterns + for (auto &pattern : tuple_items.get_patterns ()) + { + pattern->accept_vis (*this); + + if (pattern->is_marked_for_strip ()) + rust_error_at (pattern->get_locus (), + "cannot strip pattern in this position"); + // TODO: quit stripping now? or keep going? + } +} +void +AttrVisitor::visit (AST::TuplePatternItemsRanged &tuple_items) +{ + // can't strip individual patterns, only sub-patterns + for (auto &lower_pattern : tuple_items.get_lower_patterns ()) + { + lower_pattern->accept_vis (*this); + + if (lower_pattern->is_marked_for_strip ()) + rust_error_at (lower_pattern->get_locus (), + "cannot strip pattern in this position"); + // TODO: quit stripping now? or keep going? + } + for (auto &upper_pattern : tuple_items.get_upper_patterns ()) + { + upper_pattern->accept_vis (*this); + + if (upper_pattern->is_marked_for_strip ()) + rust_error_at (upper_pattern->get_locus (), + "cannot strip pattern in this position"); + // TODO: quit stripping now? or keep going? + } +} +void +AttrVisitor::visit (AST::TuplePattern &pattern) +{ + if (pattern.has_tuple_pattern_items ()) + pattern.get_items ()->accept_vis (*this); +} +void +AttrVisitor::visit (AST::GroupedPattern &pattern) +{ + // can't strip inner pattern, only sub-patterns + auto &pattern_in_parens = pattern.get_pattern_in_parens (); + + pattern_in_parens->accept_vis (*this); + + if (pattern_in_parens->is_marked_for_strip ()) + rust_error_at (pattern_in_parens->get_locus (), + "cannot strip pattern in this position"); +} +void +AttrVisitor::visit (AST::SlicePattern &pattern) +{ + // can't strip individual patterns, only sub-patterns + for (auto &item : pattern.get_items ()) + { + item->accept_vis (*this); + + if (item->is_marked_for_strip ()) + rust_error_at (item->get_locus (), + "cannot strip pattern in this position"); + // TODO: quit stripping now? or keep going? + } +} + +void +AttrVisitor::visit (AST::EmptyStmt &) +{ + // assuming no outer attributes, so nothing can happen +} +void +AttrVisitor::visit (AST::LetStmt &stmt) +{ + // initial strip test based on outer attrs + expander.expand_cfg_attrs (stmt.get_outer_attrs ()); + if (expander.fails_cfg_with_expand (stmt.get_outer_attrs ())) + { + stmt.mark_for_strip (); + return; + } + + // can't strip pattern, but call for sub-patterns + auto &pattern = stmt.get_pattern (); + pattern->accept_vis (*this); + if (pattern->is_marked_for_strip ()) + rust_error_at (pattern->get_locus (), + "cannot strip pattern in this position"); + + // similar for type + if (stmt.has_type ()) + { + expander.push_context (MacroExpander::ContextType::TYPE); + + auto &type = stmt.get_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), + "cannot strip type in this position"); + + expander.pop_context (); + } + + /* strip any internal sub-expressions - expression itself isn't + * allowed to have external attributes in this position so can't be + * stripped */ + if (stmt.has_init_expr ()) + { + auto &init_expr = stmt.get_init_expr (); + init_expr->accept_vis (*this); + + if (init_expr->is_marked_for_strip ()) + rust_error_at (init_expr->get_locus (), + "cannot strip expression in this position - outer " + "attributes not allowed"); + + maybe_expand_expr (init_expr); + } +} +void +AttrVisitor::visit (AST::ExprStmtWithoutBlock &stmt) +{ + // outer attributes associated with expr, so rely on expr + + // guard - should prevent null pointer expr + if (stmt.is_marked_for_strip ()) + return; + + // strip if expr is to be stripped + auto &expr = stmt.get_expr (); + expr->accept_vis (*this); + if (expr->is_marked_for_strip ()) + { + stmt.mark_for_strip (); + return; + } +} +void +AttrVisitor::visit (AST::ExprStmtWithBlock &stmt) +{ + // outer attributes associated with expr, so rely on expr + + // guard - should prevent null pointer expr + if (stmt.is_marked_for_strip ()) + return; + + // strip if expr is to be stripped + auto &expr = stmt.get_expr (); + expr->accept_vis (*this); + if (expr->is_marked_for_strip ()) + { + stmt.mark_for_strip (); + return; + } +} + +void +AttrVisitor::visit (AST::TraitBound &bound) +{ + // nothing in for lifetimes to strip + + // expand but don't strip type path + auto &path = bound.get_type_path (); + visit (path); + if (path.is_marked_for_strip ()) + rust_error_at (path.get_locus (), + "cannot strip type path in this position"); +} +void +AttrVisitor::visit (AST::ImplTraitType &type) +{ + // don't strip directly, only components of bounds + for (auto &bound : type.get_type_param_bounds ()) + bound->accept_vis (*this); +} +void +AttrVisitor::visit (AST::TraitObjectType &type) +{ + // don't strip directly, only components of bounds + for (auto &bound : type.get_type_param_bounds ()) + bound->accept_vis (*this); +} +void +AttrVisitor::visit (AST::ParenthesisedType &type) +{ + // expand but don't strip inner type + auto &inner_type = type.get_type_in_parens (); + inner_type->accept_vis (*this); + if (inner_type->is_marked_for_strip ()) + rust_error_at (inner_type->get_locus (), + "cannot strip type in this position"); +} +void +AttrVisitor::visit (AST::ImplTraitTypeOneBound &type) +{ + // no stripping possible + visit (type.get_trait_bound ()); +} +void +AttrVisitor::visit (AST::TraitObjectTypeOneBound &type) +{ + // no stripping possible + visit (type.get_trait_bound ()); +} +void +AttrVisitor::visit (AST::TupleType &type) +{ + // TODO: assuming that types can't be stripped as types don't have outer + // attributes + for (auto &elem_type : type.get_elems ()) + { + elem_type->accept_vis (*this); + if (elem_type->is_marked_for_strip ()) + rust_error_at (elem_type->get_locus (), + "cannot strip type in this position"); + } +} +void +AttrVisitor::visit (AST::NeverType &) +{ + // no stripping possible +} +void +AttrVisitor::visit (AST::RawPointerType &type) +{ + // expand but don't strip type pointed to + auto &pointed_type = type.get_type_pointed_to (); + pointed_type->accept_vis (*this); + if (pointed_type->is_marked_for_strip ()) + rust_error_at (pointed_type->get_locus (), + "cannot strip type in this position"); +} +void +AttrVisitor::visit (AST::ReferenceType &type) +{ + // expand but don't strip type referenced + auto &referenced_type = type.get_type_referenced (); + referenced_type->accept_vis (*this); + if (referenced_type->is_marked_for_strip ()) + rust_error_at (referenced_type->get_locus (), + "cannot strip type in this position"); +} +void +AttrVisitor::visit (AST::ArrayType &type) +{ + // expand but don't strip type referenced + auto &base_type = type.get_elem_type (); + base_type->accept_vis (*this); + if (base_type->is_marked_for_strip ()) + rust_error_at (base_type->get_locus (), + "cannot strip type in this position"); + + // same for expression + auto &size_expr = type.get_size_expr (); + size_expr->accept_vis (*this); + if (size_expr->is_marked_for_strip ()) + rust_error_at (size_expr->get_locus (), + "cannot strip expression in this position"); +} +void +AttrVisitor::visit (AST::SliceType &type) +{ + // expand but don't strip elem type + auto &elem_type = type.get_elem_type (); + elem_type->accept_vis (*this); + if (elem_type->is_marked_for_strip ()) + rust_error_at (elem_type->get_locus (), + "cannot strip type in this position"); +} +void +AttrVisitor::visit (AST::InferredType &) +{ + // none possible +} +void +AttrVisitor::visit (AST::BareFunctionType &type) +{ + // seem to be no generics + + // presumably function params can be stripped + auto ¶ms = type.get_function_params (); + for (auto it = params.begin (); it != params.end ();) + { + auto ¶m = *it; + + auto ¶m_attrs = param.get_outer_attrs (); + expander.expand_cfg_attrs (param_attrs); + if (expander.fails_cfg_with_expand (param_attrs)) + { + it = params.erase (it); + continue; + } + + expander.push_context (MacroExpander::ContextType::TYPE); + + auto &type = param.get_type (); + type->accept_vis (*this); + + maybe_expand_type (type); + + if (type->is_marked_for_strip ()) + rust_error_at (type->get_locus (), + "cannot strip type in this position"); + + expander.pop_context (); + + // increment if nothing else happens + ++it; + } + + /* TODO: assuming that variadic nature cannot be stripped. If this + * is not true, then have code here to do so. */ + + if (type.has_return_type ()) + { + // FIXME: Can we have type expansion in this position? + // In that case, we need to handle AST::TypeNoBounds on top of just + // AST::Types + auto &return_type = type.get_return_type (); + return_type->accept_vis (*this); + if (return_type->is_marked_for_strip ()) + rust_error_at (return_type->get_locus (), + "cannot strip type in this position"); + } + + // no where clause, apparently +} +void +AttrVisitor::maybe_expand_expr (std::unique_ptr &expr) +{ + auto final_fragment = expand_macro_fragment_recursive (); + if (final_fragment.should_expand ()) + expr = final_fragment.take_expression_fragment (); +} + +void +AttrVisitor::maybe_expand_type (std::unique_ptr &type) +{ + auto final_fragment = expand_macro_fragment_recursive (); + if (final_fragment.should_expand ()) + type = final_fragment.take_type_fragment (); +} +} // namespace Rust diff --git a/gcc/rust/expand/rust-attribute-visitor.h b/gcc/rust/expand/rust-attribute-visitor.h new file mode 100644 index 00000000000..0f9d1065334 --- /dev/null +++ b/gcc/rust/expand/rust-attribute-visitor.h @@ -0,0 +1,316 @@ +// 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 +// . + +#include "rust-ast-visitor.h" +#include "rust-ast.h" +#include "rust-macro-expand.h" + +namespace Rust { +// Visitor used to expand attributes. +class AttrVisitor : public AST::ASTVisitor +{ +private: + MacroExpander &expander; + void maybe_expand_expr (std::unique_ptr &expr); + void maybe_expand_type (std::unique_ptr &expr); + +public: + AttrVisitor (MacroExpander &expander) : expander (expander) {} + + void expand_struct_fields (std::vector &fields); + void expand_tuple_fields (std::vector &fields); + void expand_function_params (std::vector ¶ms); + void expand_generic_args (AST::GenericArgs &args); + void expand_qualified_path_type (AST::QualifiedPathType &path_type); + void expand_closure_params (std::vector ¶ms); + void expand_self_param (AST::SelfParam &self_param); + void expand_where_clause (AST::WhereClause &where_clause); + void expand_trait_function_decl (AST::TraitFunctionDecl &decl); + void expand_trait_method_decl (AST::TraitMethodDecl &decl); + + /** + * Expand The current macro fragment recursively until it could not be + * expanded further. + * + * The return value checking works because correctly + * expanded fragment can never be an error (if the fragment can not be + * expanded, a stand-in error fragment will be returned; for fragments that + * could not be further expanded: the fragment prior to the expansion failure + * will be returned). + * + * @return Either the expanded fragment or an empty errored-out fragment + * indicating an expansion failure. + */ + AST::ASTFragment expand_macro_fragment_recursive () + { + auto fragment = expander.take_expanded_fragment (*this); + unsigned int original_depth = expander.expansion_depth; + auto final_fragment = AST::ASTFragment ({}, true); + + while (fragment.should_expand ()) + { + final_fragment = std::move (fragment); + expander.expansion_depth++; + // further expand the previously expanded macro fragment + auto new_fragment = expander.take_expanded_fragment (*this); + if (new_fragment.is_error ()) + break; + fragment = std::move (new_fragment); + } + expander.expansion_depth = original_depth; + return final_fragment; + } + + /** + * Expand a set of values, erasing them if they are marked for strip, and + * replacing them with expanded macro nodes if necessary. + * This function is slightly different from `expand_pointer_allow_strip` as + * it can only be called in certain expansion contexts - where macro + * invocations are allowed. + * + * @param ctx Context to use for macro expansion + * @param values Iterable reference over values to replace or erase + * @param extractor Function to call when replacing values with the content + * of an expanded AST node + */ + template + void expand_macro_children (MacroExpander::ContextType ctx, T &values, + std::function extractor) + { + expander.push_context (ctx); + + for (auto it = values.begin (); it != values.end ();) + { + auto &value = *it; + + // mark for stripping if required + value->accept_vis (*this); + + // recursively expand the children + auto final_fragment = expand_macro_fragment_recursive (); + + if (final_fragment.should_expand ()) + { + it = values.erase (it); + for (auto &node : final_fragment.get_nodes ()) + { + auto new_node = extractor (node); + if (new_node != nullptr && !new_node->is_marked_for_strip ()) + { + it = values.insert (it, std::move (new_node)); + it++; + } + } + } + else if (value->is_marked_for_strip ()) + { + it = values.erase (it); + } + else + { + ++it; + } + } + + expander.pop_context (); + } + + template void expand_pointer_allow_strip (T &values) + { + for (auto it = values.begin (); it != values.end ();) + { + auto &value = *it; + + // mark for stripping if required + value->accept_vis (*this); + if (value->is_marked_for_strip ()) + { + it = values.erase (it); + } + else + { + ++it; + } + } + } + + void visit (AST::Token &) override; + void visit (AST::DelimTokenTree &) override; + void visit (AST::AttrInputMetaItemContainer &) override; + void visit (AST::IdentifierExpr &ident_expr) override; + void visit (AST::Lifetime &) override; + void visit (AST::LifetimeParam &) override; + void visit (AST::ConstGenericParam &) override; + + void visit (AST::MacroInvocation ¯o_invoc) override; + + void visit (AST::PathInExpression &path) override; + void visit (AST::TypePathSegment &) override; + void visit (AST::TypePathSegmentGeneric &segment) override; + void visit (AST::TypePathSegmentFunction &segment) override; + void visit (AST::TypePath &path) override; + void visit (AST::QualifiedPathInExpression &path) override; + void visit (AST::QualifiedPathInType &path) override; + + void visit (AST::LiteralExpr &expr) override; + void visit (AST::AttrInputLiteral &) override; + void visit (AST::MetaItemLitExpr &) override; + void visit (AST::MetaItemPathLit &) override; + void visit (AST::BorrowExpr &expr) override; + void visit (AST::DereferenceExpr &expr) override; + void visit (AST::ErrorPropagationExpr &expr) override; + void visit (AST::NegationExpr &expr) override; + void visit (AST::ArithmeticOrLogicalExpr &expr) override; + void visit (AST::ComparisonExpr &expr) override; + void visit (AST::LazyBooleanExpr &expr) override; + void visit (AST::TypeCastExpr &expr) override; + void visit (AST::AssignmentExpr &expr) override; + void visit (AST::CompoundAssignmentExpr &expr) override; + void visit (AST::GroupedExpr &expr) override; + void visit (AST::ArrayElemsValues &elems) override; + void visit (AST::ArrayElemsCopied &elems) override; + void visit (AST::ArrayExpr &expr) override; + void visit (AST::ArrayIndexExpr &expr) override; + void visit (AST::TupleExpr &expr) override; + void visit (AST::TupleIndexExpr &expr) override; + void visit (AST::StructExprStruct &expr) override; + void visit (AST::StructExprFieldIdentifier &) override; + void visit (AST::StructExprFieldIdentifierValue &field) override; + + void visit (AST::StructExprFieldIndexValue &field) override; + void visit (AST::StructExprStructFields &expr) override; + void visit (AST::StructExprStructBase &expr) override; + void visit (AST::CallExpr &expr) override; + void visit (AST::MethodCallExpr &expr) override; + void visit (AST::FieldAccessExpr &expr) override; + void visit (AST::ClosureExprInner &expr) override; + + void visit (AST::BlockExpr &expr) override; + + void visit (AST::ClosureExprInnerTyped &expr) override; + void visit (AST::ContinueExpr &expr) override; + void visit (AST::BreakExpr &expr) override; + void visit (AST::RangeFromToExpr &expr) override; + void visit (AST::RangeFromExpr &expr) override; + void visit (AST::RangeToExpr &expr) override; + void visit (AST::RangeFullExpr &) override; + void visit (AST::RangeFromToInclExpr &expr) override; + void visit (AST::RangeToInclExpr &expr) override; + void visit (AST::ReturnExpr &expr) override; + void visit (AST::UnsafeBlockExpr &expr) override; + void visit (AST::LoopExpr &expr) override; + void visit (AST::WhileLoopExpr &expr) override; + void visit (AST::WhileLetLoopExpr &expr) override; + void visit (AST::ForLoopExpr &expr) override; + void visit (AST::IfExpr &expr) override; + void visit (AST::IfExprConseqElse &expr) override; + void visit (AST::IfExprConseqIf &expr) override; + void visit (AST::IfExprConseqIfLet &expr) override; + void visit (AST::IfLetExpr &expr) override; + void visit (AST::IfLetExprConseqElse &expr) override; + void visit (AST::IfLetExprConseqIf &expr) override; + void visit (AST::IfLetExprConseqIfLet &expr) override; + void visit (AST::MatchExpr &expr) override; + void visit (AST::AwaitExpr &expr) override; + void visit (AST::AsyncBlockExpr &expr) override; + void visit (AST::TypeParam ¶m) override; + void visit (AST::LifetimeWhereClauseItem &) override; + void visit (AST::TypeBoundWhereClauseItem &item) override; + void visit (AST::Method &method) override; + void visit (AST::Module &module) override; + void visit (AST::ExternCrate &crate) override; + void visit (AST::UseTreeGlob &) override; + void visit (AST::UseTreeList &) override; + void visit (AST::UseTreeRebind &) override; + void visit (AST::UseDeclaration &use_decl) override; + void visit (AST::Function &function) override; + void visit (AST::TypeAlias &type_alias) override; + void visit (AST::StructStruct &struct_item) override; + void visit (AST::TupleStruct &tuple_struct) override; + void visit (AST::EnumItem &item) override; + void visit (AST::EnumItemTuple &item) override; + void visit (AST::EnumItemStruct &item) override; + void visit (AST::EnumItemDiscriminant &item) override; + void visit (AST::Enum &enum_item) override; + void visit (AST::Union &union_item) override; + void visit (AST::ConstantItem &const_item) override; + void visit (AST::StaticItem &static_item) override; + void visit (AST::TraitItemFunc &item) override; + void visit (AST::TraitItemMethod &item) override; + void visit (AST::TraitItemConst &item) override; + void visit (AST::TraitItemType &item) override; + void visit (AST::Trait &trait) override; + void visit (AST::InherentImpl &impl) override; + void visit (AST::TraitImpl &impl) override; + void visit (AST::ExternalStaticItem &item) override; + void visit (AST::ExternalFunctionItem &item) override; + void visit (AST::ExternBlock &block) override; + + // I don't think it would be possible to strip macros without expansion + void visit (AST::MacroMatchFragment &) override; + void visit (AST::MacroMatchRepetition &) override; + void visit (AST::MacroMatcher &) override; + void visit (AST::MacroRulesDefinition &rules_def) override; + void visit (AST::MetaItemPath &) override; + void visit (AST::MetaItemSeq &) override; + void visit (AST::MetaWord &) override; + void visit (AST::MetaNameValueStr &) override; + void visit (AST::MetaListPaths &) override; + void visit (AST::MetaListNameValueStr &) override; + void visit (AST::LiteralPattern &) override; + void visit (AST::IdentifierPattern &pattern) override; + void visit (AST::WildcardPattern &) override; + void visit (AST::RangePatternBoundLiteral &) override; + void visit (AST::RangePatternBoundPath &bound) override; + void visit (AST::RangePatternBoundQualPath &bound) override; + void visit (AST::RangePattern &pattern) override; + void visit (AST::ReferencePattern &pattern) override; + void visit (AST::StructPatternFieldTuplePat &field) override; + void visit (AST::StructPatternFieldIdentPat &field) override; + void visit (AST::StructPatternFieldIdent &field) override; + void visit (AST::StructPattern &pattern) override; + void visit (AST::TupleStructItemsNoRange &tuple_items) override; + void visit (AST::TupleStructItemsRange &tuple_items) override; + void visit (AST::TupleStructPattern &pattern) override; + void visit (AST::TuplePatternItemsMultiple &tuple_items) override; + void visit (AST::TuplePatternItemsRanged &tuple_items) override; + void visit (AST::TuplePattern &pattern) override; + void visit (AST::GroupedPattern &pattern) override; + void visit (AST::SlicePattern &pattern) override; + + void visit (AST::EmptyStmt &) override; + void visit (AST::LetStmt &stmt) override; + void visit (AST::ExprStmtWithoutBlock &stmt) override; + void visit (AST::ExprStmtWithBlock &stmt) override; + + void visit (AST::TraitBound &bound) override; + void visit (AST::ImplTraitType &type) override; + void visit (AST::TraitObjectType &type) override; + void visit (AST::ParenthesisedType &type) override; + void visit (AST::ImplTraitTypeOneBound &type) override; + void visit (AST::TraitObjectTypeOneBound &type) override; + void visit (AST::TupleType &type) override; + void visit (AST::NeverType &) override; + void visit (AST::RawPointerType &type) override; + void visit (AST::ReferenceType &type) override; + void visit (AST::ArrayType &type) override; + void visit (AST::SliceType &type) override; + void visit (AST::InferredType &) override; + void visit (AST::BareFunctionType &type) override; +}; +} // namespace Rust diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc new file mode 100644 index 00000000000..5eace13d197 --- /dev/null +++ b/gcc/rust/expand/rust-macro-builtins.cc @@ -0,0 +1,484 @@ +// 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 +// . + +#include "rust-macro-builtins.h" +#include "rust-diagnostics.h" +#include "rust-expr.h" +#include "rust-session-manager.h" +#include "rust-macro-invoc-lexer.h" +#include "rust-lex.h" +#include "rust-parse.h" + +namespace Rust { +namespace { +std::unique_ptr +make_string (Location locus, std::string value) +{ + return std::unique_ptr ( + new AST::LiteralExpr (value, AST::Literal::STRING, + PrimitiveCoreType::CORETYPE_STR, {}, locus)); +} + +/* Match the end token of a macro given the start delimiter of the macro */ + +static inline TokenId +macro_end_token (AST::DelimTokenTree &invoc_token_tree, + Parser &parser) +{ + auto last_token_id = TokenId::RIGHT_CURLY; + switch (invoc_token_tree.get_delim_type ()) + { + case AST::DelimType::PARENS: + last_token_id = TokenId::RIGHT_PAREN; + rust_assert (parser.skip_token (LEFT_PAREN)); + break; + + case AST::DelimType::CURLY: + rust_assert (parser.skip_token (LEFT_CURLY)); + break; + + case AST::DelimType::SQUARE: + last_token_id = TokenId::RIGHT_SQUARE; + rust_assert (parser.skip_token (LEFT_SQUARE)); + break; + } + + return last_token_id; +} + +/* Parse a single string literal from the given delimited token tree, + and return the LiteralExpr for it. Allow for an optional trailing comma, + but otherwise enforce that these are the only tokens. */ + +std::unique_ptr +parse_single_string_literal (AST::DelimTokenTree &invoc_token_tree, + Location invoc_locus) +{ + MacroInvocLexer lex (invoc_token_tree.to_token_stream ()); + Parser parser (lex); + + auto last_token_id = macro_end_token (invoc_token_tree, parser); + + std::unique_ptr lit_expr = nullptr; + + if (parser.peek_current_token ()->get_id () == STRING_LITERAL) + { + lit_expr = parser.parse_literal_expr (); + parser.maybe_skip_token (COMMA); + if (parser.peek_current_token ()->get_id () != last_token_id) + { + lit_expr = nullptr; + rust_error_at (invoc_locus, "macro takes 1 argument"); + } + } + else if (parser.peek_current_token ()->get_id () == last_token_id) + rust_error_at (invoc_locus, "macro takes 1 argument"); + else + rust_error_at (invoc_locus, "argument must be a string literal"); + + parser.skip_token (last_token_id); + + return lit_expr; +} + +/* Treat PATH as a path relative to the source file currently being + compiled, and return the absolute path for it. */ + +std::string +source_relative_path (std::string path, Location locus) +{ + std::string compile_fname + = Session::get_instance ().linemap->location_file (locus); + + auto dir_separator_pos = compile_fname.rfind (file_separator); + + /* If there is no file_separator in the path, use current dir ('.'). */ + std::string dirname; + if (dir_separator_pos == std::string::npos) + dirname = std::string (".") + file_separator; + else + dirname = compile_fname.substr (0, dir_separator_pos) + file_separator; + + return dirname + path; +} + +/* Read the full contents of the file FILENAME and return them in a vector. + FIXME: platform specific. */ + +std::vector +load_file_bytes (const char *filename) +{ + RAIIFile file_wrap (filename); + if (file_wrap.get_raw () == nullptr) + { + rust_error_at (Location (), "cannot open filename %s: %m", filename); + return std::vector (); + } + + FILE *f = file_wrap.get_raw (); + fseek (f, 0L, SEEK_END); + long fsize = ftell (f); + fseek (f, 0L, SEEK_SET); + + std::vector buf (fsize); + + if (fread (&buf[0], fsize, 1, f) != 1) + { + rust_error_at (Location (), "error reading file %s: %m", filename); + return std::vector (); + } + + return buf; +} +} // namespace + +AST::ASTFragment +MacroBuiltin::assert (Location invoc_locus, AST::MacroInvocData &invoc) +{ + rust_debug ("assert!() called"); + + return AST::ASTFragment::create_error (); +} + +AST::ASTFragment +MacroBuiltin::file (Location invoc_locus, AST::MacroInvocData &invoc) +{ + auto current_file + = Session::get_instance ().linemap->location_file (invoc_locus); + auto file_str = AST::SingleASTNode (make_string (invoc_locus, current_file)); + + return AST::ASTFragment ({file_str}); +} + +AST::ASTFragment +MacroBuiltin::column (Location invoc_locus, AST::MacroInvocData &invoc) +{ + auto current_column + = Session::get_instance ().linemap->location_to_column (invoc_locus); + + auto column_no = AST::SingleASTNode (std::unique_ptr ( + new AST::LiteralExpr (std::to_string (current_column), AST::Literal::INT, + PrimitiveCoreType::CORETYPE_U32, {}, invoc_locus))); + + return AST::ASTFragment ({column_no}); +} + +/* Expand builtin macro include_bytes!("filename"), which includes the contents + of the given file as reference to a byte array. Yields an expression of type + &'static [u8; N]. */ + +AST::ASTFragment +MacroBuiltin::include_bytes (Location invoc_locus, AST::MacroInvocData &invoc) +{ + /* Get target filename from the macro invocation, which is treated as a path + relative to the include!-ing file (currently being compiled). */ + auto lit_expr + = parse_single_string_literal (invoc.get_delim_tok_tree (), invoc_locus); + if (lit_expr == nullptr) + return AST::ASTFragment::create_error (); + + std::string target_filename + = source_relative_path (lit_expr->as_string (), invoc_locus); + + std::vector bytes = load_file_bytes (target_filename.c_str ()); + + /* Is there a more efficient way to do this? */ + std::vector> elts; + for (uint8_t b : bytes) + { + elts.emplace_back ( + new AST::LiteralExpr (std::string (1, (char) b), AST::Literal::BYTE, + PrimitiveCoreType::CORETYPE_U8, + {} /* outer_attrs */, invoc_locus)); + } + + auto elems = std::unique_ptr ( + new AST::ArrayElemsValues (std::move (elts), invoc_locus)); + + auto array = std::unique_ptr ( + new AST::ArrayExpr (std::move (elems), {}, {}, invoc_locus)); + + auto borrow = std::unique_ptr ( + new AST::BorrowExpr (std::move (array), false, false, {}, invoc_locus)); + + auto node = AST::SingleASTNode (std::move (borrow)); + return AST::ASTFragment ({node}); +} + +/* Expand builtin macro include_str!("filename"), which includes the contents + of the given file as a string. The file must be UTF-8 encoded. Yields an + expression of type &'static str. */ + +AST::ASTFragment +MacroBuiltin::include_str (Location invoc_locus, AST::MacroInvocData &invoc) +{ + /* Get target filename from the macro invocation, which is treated as a path + relative to the include!-ing file (currently being compiled). */ + auto lit_expr + = parse_single_string_literal (invoc.get_delim_tok_tree (), invoc_locus); + if (lit_expr == nullptr) + return AST::ASTFragment::create_error (); + + std::string target_filename + = source_relative_path (lit_expr->as_string (), invoc_locus); + + std::vector bytes = load_file_bytes (target_filename.c_str ()); + + /* FIXME: Enforce that the file contents are valid UTF-8. */ + std::string str ((const char *) &bytes[0], bytes.size ()); + + auto node = AST::SingleASTNode (make_string (invoc_locus, str)); + return AST::ASTFragment ({node}); +} + +/* Expand builtin macro compile_error!("error"), which forces a compile error + during the compile time. */ +AST::ASTFragment +MacroBuiltin::compile_error (Location invoc_locus, AST::MacroInvocData &invoc) +{ + auto lit_expr + = parse_single_string_literal (invoc.get_delim_tok_tree (), invoc_locus); + if (lit_expr == nullptr) + return AST::ASTFragment::create_error (); + + std::string error_string = lit_expr->as_string (); + rust_error_at (invoc_locus, "%s", error_string.c_str ()); + + return AST::ASTFragment::create_error (); +} + +/* Expand builtin macro concat!(), which joins all the literal parameters + into a string with no delimiter. */ + +AST::ASTFragment +MacroBuiltin::concat (Location invoc_locus, AST::MacroInvocData &invoc) +{ + auto invoc_token_tree = invoc.get_delim_tok_tree (); + MacroInvocLexer lex (invoc_token_tree.to_token_stream ()); + Parser parser (lex); + + auto str = std::string (); + bool has_error = false; + + auto last_token_id = macro_end_token (invoc_token_tree, parser); + + /* NOTE: concat! could accept no argument, so we don't have any checks here */ + while (parser.peek_current_token ()->get_id () != last_token_id) + { + auto lit_expr = parser.parse_literal_expr (); + if (lit_expr) + { + str += lit_expr->as_string (); + } + else + { + auto current_token = parser.peek_current_token (); + rust_error_at (current_token->get_locus (), + "argument must be a constant literal"); + has_error = true; + // Just crash if the current token can't be skipped + rust_assert (parser.skip_token (current_token->get_id ())); + } + parser.maybe_skip_token (COMMA); + } + + parser.skip_token (last_token_id); + + if (has_error) + return AST::ASTFragment::create_error (); + + auto node = AST::SingleASTNode (make_string (invoc_locus, str)); + return AST::ASTFragment ({node}); +} + +/* Expand builtin macro env!(), which inspects an environment variable at + compile time. */ + +AST::ASTFragment +MacroBuiltin::env (Location invoc_locus, AST::MacroInvocData &invoc) +{ + auto invoc_token_tree = invoc.get_delim_tok_tree (); + MacroInvocLexer lex (invoc_token_tree.to_token_stream ()); + Parser parser (lex); + + auto last_token_id = macro_end_token (invoc_token_tree, parser); + + if (parser.peek_current_token ()->get_id () != STRING_LITERAL) + { + if (parser.peek_current_token ()->get_id () == last_token_id) + rust_error_at (invoc_locus, "env! takes 1 or 2 arguments"); + else + rust_error_at (parser.peek_current_token ()->get_locus (), + "argument must be a string literal"); + return AST::ASTFragment::create_error (); + } + + auto lit_expr = parser.parse_literal_expr (); + auto comma_skipped = parser.maybe_skip_token (COMMA); + + std::unique_ptr error_expr = nullptr; + + if (parser.peek_current_token ()->get_id () != last_token_id) + { + if (!comma_skipped) + { + rust_error_at (parser.peek_current_token ()->get_locus (), + "expected token: %<,%>"); + return AST::ASTFragment::create_error (); + } + if (parser.peek_current_token ()->get_id () != STRING_LITERAL) + { + rust_error_at (parser.peek_current_token ()->get_locus (), + "argument must be a string literal"); + return AST::ASTFragment::create_error (); + } + + error_expr = parser.parse_literal_expr (); + parser.maybe_skip_token (COMMA); + } + + if (parser.peek_current_token ()->get_id () != last_token_id) + { + rust_error_at (invoc_locus, "env! takes 1 or 2 arguments"); + return AST::ASTFragment::create_error (); + } + + parser.skip_token (last_token_id); + + auto env_value = getenv (lit_expr->as_string ().c_str ()); + + if (env_value == nullptr) + { + if (error_expr == nullptr) + rust_error_at (invoc_locus, "environment variable %qs not defined", + lit_expr->as_string ().c_str ()); + else + rust_error_at (invoc_locus, "%s", error_expr->as_string ().c_str ()); + return AST::ASTFragment::create_error (); + } + + auto node = AST::SingleASTNode (make_string (invoc_locus, env_value)); + return AST::ASTFragment ({node}); +} + +AST::ASTFragment +MacroBuiltin::cfg (Location invoc_locus, AST::MacroInvocData &invoc) +{ + // only parse if not already parsed + if (!invoc.is_parsed ()) + { + std::unique_ptr converted_input ( + invoc.get_delim_tok_tree ().parse_to_meta_item ()); + + if (converted_input == nullptr) + { + rust_debug ("DEBUG: failed to parse macro to meta item"); + // TODO: do something now? is this an actual error? + } + else + { + std::vector> meta_items ( + std::move (converted_input->get_items ())); + invoc.set_meta_item_output (std::move (meta_items)); + } + } + + /* TODO: assuming that cfg! macros can only have one meta item inner, like cfg + * attributes */ + if (invoc.get_meta_items ().size () != 1) + return AST::ASTFragment::create_error (); + + bool result = invoc.get_meta_items ()[0]->check_cfg_predicate ( + Session::get_instance ()); + auto literal_exp = AST::SingleASTNode (std::unique_ptr ( + new AST::LiteralExpr (result ? "true" : "false", AST::Literal::BOOL, + PrimitiveCoreType::CORETYPE_BOOL, {}, invoc_locus))); + + return AST::ASTFragment ({literal_exp}); +} + +/* Expand builtin macro include!(), which includes a source file at the current + scope compile time. */ + +AST::ASTFragment +MacroBuiltin::include (Location invoc_locus, AST::MacroInvocData &invoc) +{ + /* Get target filename from the macro invocation, which is treated as a path + relative to the include!-ing file (currently being compiled). */ + auto lit_expr + = parse_single_string_literal (invoc.get_delim_tok_tree (), invoc_locus); + if (lit_expr == nullptr) + return AST::ASTFragment::create_error (); + + std::string filename + = source_relative_path (lit_expr->as_string (), invoc_locus); + auto target_filename + = Rust::Session::get_instance ().include_extra_file (std::move (filename)); + + RAIIFile target_file (target_filename); + Linemap *linemap = Session::get_instance ().linemap; + + if (!target_file.ok ()) + { + rust_error_at (lit_expr->get_locus (), + "cannot open included file %qs: %m", target_filename); + return AST::ASTFragment::create_error (); + } + + rust_debug ("Attempting to parse included file %s", target_filename); + + Lexer lex (target_filename, std::move (target_file), linemap); + Parser parser (lex); + + auto parsed_items = parser.parse_items (); + bool has_error = !parser.get_errors ().empty (); + + for (const auto &error : parser.get_errors ()) + error.emit_error (); + + if (has_error) + { + // inform the user that the errors above are from a included file + rust_inform (invoc_locus, "included from here"); + return AST::ASTFragment::create_error (); + } + + std::vector nodes{}; + for (auto &item : parsed_items) + { + AST::SingleASTNode node (std::move (item)); + nodes.push_back (node); + } + + return AST::ASTFragment (nodes); +} + +AST::ASTFragment +MacroBuiltin::line (Location invoc_locus, AST::MacroInvocData &invoc) +{ + auto current_line + = Session::get_instance ().linemap->location_to_line (invoc_locus); + + auto line_no = AST::SingleASTNode (std::unique_ptr ( + new AST::LiteralExpr (std::to_string (current_line), AST::Literal::INT, + PrimitiveCoreType::CORETYPE_U32, {}, invoc_locus))); + + return AST::ASTFragment ({line_no}); +} + +} // namespace Rust diff --git a/gcc/rust/expand/rust-macro-builtins.h b/gcc/rust/expand/rust-macro-builtins.h new file mode 100644 index 00000000000..91f3727d450 --- /dev/null +++ b/gcc/rust/expand/rust-macro-builtins.h @@ -0,0 +1,107 @@ +// 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_MACRO_BUILTINS_H +#define RUST_MACRO_BUILTINS_H + +#include "rust-ast.h" +#include "rust-location.h" + +/** + * This class provides a list of builtin macros implemented by the compiler. + * The functions defined are called "builtin transcribers" in that they replace + * the transcribing part of a macro definition. + * + * Like regular macro transcribers, they are responsible for building and + * returning an AST fragment: basically a vector of AST nodes put together. + * + * Unlike regular declarative macros where each match arm has its own associated + * transcriber, builtin transcribers are responsible for handling all match arms + * of the macro. This means that you should take extra care when implementing a + * builtin containing multiple match arms: You will probably need to do some + * lookahead in order to determine which match arm the user intended to use. + * + * An example of this is the `assert!()` macro: + * + * ``` + * macro_rules! assert { + * ($cond:expr $(,)?) => {{ ... }}; + * ($cond : expr, $ ($arg : tt) +) = > {{ ... }}; + * } + * ``` + * + * If more tokens exist beyond the optional comma, they need to be handled as + * a token-tree for a custom panic message. + * + * These builtin macros with empty transcribers are defined in the standard + * library. They are marked with a special attribute, `#[rustc_builtin_macro]`. + * When this attribute is present on a macro definition, the compiler should + * look for an associated transcriber in the mappings. Meaning that you must + * remember to insert your transcriber in the `builtin_macros` map of the + *`Mappings`. + * + * This map is built as a static variable in the `insert_macro_def()` method + * of the `Mappings` class. + */ + +/* If assert is defined as a macro this file will not parse, so undefine this + before continuing. */ +#ifdef assert +#undef assert +#endif + +namespace Rust { +class MacroBuiltin +{ +public: + static AST::ASTFragment assert (Location invoc_locus, + AST::MacroInvocData &invoc); + + static AST::ASTFragment file (Location invoc_locus, + AST::MacroInvocData &invoc); + + static AST::ASTFragment column (Location invoc_locus, + AST::MacroInvocData &invoc); + + static AST::ASTFragment include_bytes (Location invoc_locus, + AST::MacroInvocData &invoc); + + static AST::ASTFragment include_str (Location invoc_locus, + AST::MacroInvocData &invoc); + + static AST::ASTFragment compile_error (Location invoc_locus, + AST::MacroInvocData &invoc); + + static AST::ASTFragment concat (Location invoc_locus, + AST::MacroInvocData &invoc); + + static AST::ASTFragment env (Location invoc_locus, + AST::MacroInvocData &invoc); + + static AST::ASTFragment cfg (Location invoc_locus, + AST::MacroInvocData &invoc); + + static AST::ASTFragment include (Location invoc_locus, + AST::MacroInvocData &invoc); + + static AST::ASTFragment line (Location invoc_locus, + AST::MacroInvocData &invoc); +}; +} // namespace Rust + +#endif // RUST_MACRO_BUILTINS_H diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc new file mode 100644 index 00000000000..1d57e394220 --- /dev/null +++ b/gcc/rust/expand/rust-macro-expand.cc @@ -0,0 +1,1012 @@ +// 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 +// . + +#include "rust-macro-expand.h" +#include "rust-macro-substitute-ctx.h" +#include "rust-ast-full.h" +#include "rust-ast-visitor.h" +#include "rust-diagnostics.h" +#include "rust-parse.h" +#include "rust-attribute-visitor.h" + +namespace Rust { +AST::ASTFragment +MacroExpander::expand_decl_macro (Location invoc_locus, + AST::MacroInvocData &invoc, + AST::MacroRulesDefinition &rules_def, + bool semicolon) +{ + // ensure that both invocation and rules are in a valid state + rust_assert (!invoc.is_marked_for_strip ()); + rust_assert (!rules_def.is_marked_for_strip ()); + rust_assert (rules_def.get_macro_rules ().size () > 0); + + /* probably something here about parsing invoc and rules def token trees to + * token stream. if not, how would parser handle the captures of exprs and + * stuff? on the other hand, token trees may be kind of useful in rules def as + * creating a point where recursion can occur (like having + * "compare_macro_match" and then it calling itself when it finds delimiters) + */ + + /* find matching rule to invoc token tree, based on macro rule's matcher. if + * none exist, error. + * - specifically, check each matcher in order. if one fails to match, move + * onto next. */ + /* TODO: does doing this require parsing expressions and whatever in the + * invoc? if so, might as well save the results if referenced using $ or + * whatever. If not, do another pass saving them. Except this is probably + * useless as different rules could have different starting points for exprs + * or whatever. Decision trees could avoid this, but they have their own + * issues. */ + /* TODO: will need to modify the parser so that it can essentially "catch" + * errors - maybe "try_parse_expr" or whatever methods. */ + // this technically creates a back-tracking parser - this will be the + // implementation style + + /* then, after results are saved, generate the macro output from the + * transcriber token tree. if i understand this correctly, the macro + * invocation gets replaced by the transcriber tokens, except with + * substitutions made (e.g. for $i variables) */ + + /* TODO: it is probably better to modify AST::Token to store a pointer to a + * Lexer::Token (rather than being converted) - i.e. not so much have + * AST::Token as a Token but rather a TokenContainer (as it is another type of + * TokenTree). This will prevent re-conversion of Tokens between each type + * all the time, while still allowing the heterogenous storage of token trees. + */ + + AST::DelimTokenTree &invoc_token_tree = invoc.get_delim_tok_tree (); + + // find matching arm + AST::MacroRule *matched_rule = nullptr; + std::map matched_fragments; + for (auto &rule : rules_def.get_rules ()) + { + sub_stack.push (); + bool did_match_rule = try_match_rule (rule, invoc_token_tree); + matched_fragments = sub_stack.pop (); + + if (did_match_rule) + { + // // Debugging + // for (auto &kv : matched_fragments) + // rust_debug ("[fragment]: %s (%ld - %s)", kv.first.c_str (), + // kv.second.get_fragments ().size (), + // kv.second.get_kind () + // == MatchedFragmentContainer::Kind::Repetition + // ? "repetition" + // : "metavar"); + + matched_rule = &rule; + break; + } + } + + if (matched_rule == nullptr) + { + RichLocation r (invoc_locus); + r.add_range (rules_def.get_locus ()); + rust_error_at (r, "Failed to match any rule within macro"); + return AST::ASTFragment::create_error (); + } + + return transcribe_rule (*matched_rule, invoc_token_tree, matched_fragments, + semicolon, peek_context ()); +} + +void +MacroExpander::expand_invoc (AST::MacroInvocation &invoc, bool has_semicolon) +{ + if (depth_exceeds_recursion_limit ()) + { + rust_error_at (invoc.get_locus (), "reached recursion limit"); + return; + } + + AST::MacroInvocData &invoc_data = invoc.get_invoc_data (); + + // ?? + // switch on type of macro: + // - '!' syntax macro (inner switch) + // - procedural macro - "A token-based function-like macro" + // - 'macro_rules' (by example/pattern-match) macro? or not? "an + // AST-based function-like macro" + // - else is unreachable + // - attribute syntax macro (inner switch) + // - procedural macro attribute syntax - "A token-based attribute + // macro" + // - legacy macro attribute syntax? - "an AST-based attribute macro" + // - non-macro attribute: mark known + // - else is unreachable + // - derive macro (inner switch) + // - derive or legacy derive - "token-based" vs "AST-based" + // - else is unreachable + // - derive container macro - unreachable + + // lookup the rules for this macro + NodeId resolved_node = UNKNOWN_NODEID; + NodeId source_node = UNKNOWN_NODEID; + if (has_semicolon) + source_node = invoc.get_macro_node_id (); + else + source_node = invoc.get_pattern_node_id (); + auto seg + = Resolver::CanonicalPath::new_seg (source_node, + invoc_data.get_path ().as_string ()); + + bool found = resolver->get_macro_scope ().lookup (seg, &resolved_node); + if (!found) + { + rust_error_at (invoc.get_locus (), "unknown macro: [%s]", + seg.get ().c_str ()); + return; + } + + // lookup the rules + AST::MacroRulesDefinition *rules_def = nullptr; + bool ok = mappings->lookup_macro_def (resolved_node, &rules_def); + rust_assert (ok); + + auto fragment = AST::ASTFragment::create_error (); + + if (rules_def->is_builtin ()) + fragment + = rules_def->get_builtin_transcriber () (invoc.get_locus (), invoc_data); + else + fragment = expand_decl_macro (invoc.get_locus (), invoc_data, *rules_def, + has_semicolon); + + set_expanded_fragment (std::move (fragment)); +} + +/* Determines whether any cfg predicate is false and hence item with attributes + * should be stripped. Note that attributes must be expanded before calling. */ +bool +MacroExpander::fails_cfg (const AST::AttrVec &attrs) const +{ + for (const auto &attr : attrs) + { + if (attr.get_path () == "cfg" && !attr.check_cfg_predicate (session)) + return true; + } + return false; +} + +/* Determines whether any cfg predicate is false and hence item with attributes + * should be stripped. Will expand attributes as well. */ +bool +MacroExpander::fails_cfg_with_expand (AST::AttrVec &attrs) const +{ + // TODO: maybe have something that strips cfg attributes that evaluate true? + for (auto &attr : attrs) + { + if (attr.get_path () == "cfg") + { + if (!attr.is_parsed_to_meta_item ()) + attr.parse_attr_to_meta_item (); + + // DEBUG + if (!attr.is_parsed_to_meta_item ()) + rust_debug ("failed to parse attr to meta item, right before " + "cfg predicate check"); + else + rust_debug ("attr has been successfully parsed to meta item, " + "right before cfg predicate check"); + + if (!attr.check_cfg_predicate (session)) + { + // DEBUG + rust_debug ( + "cfg predicate failed for attribute: \033[0;31m'%s'\033[0m", + attr.as_string ().c_str ()); + + return true; + } + else + { + // DEBUG + rust_debug ("cfg predicate succeeded for attribute: " + "\033[0;31m'%s'\033[0m", + attr.as_string ().c_str ()); + } + } + } + return false; +} + +// Expands cfg_attr attributes. +void +MacroExpander::expand_cfg_attrs (AST::AttrVec &attrs) +{ + for (std::size_t i = 0; i < attrs.size (); i++) + { + auto &attr = attrs[i]; + if (attr.get_path () == "cfg_attr") + { + if (!attr.is_parsed_to_meta_item ()) + attr.parse_attr_to_meta_item (); + + if (attr.check_cfg_predicate (session)) + { + // split off cfg_attr + AST::AttrVec new_attrs = attr.separate_cfg_attrs (); + + // remove attr from vector + attrs.erase (attrs.begin () + i); + + // add new attrs to vector + attrs.insert (attrs.begin () + i, + std::make_move_iterator (new_attrs.begin ()), + std::make_move_iterator (new_attrs.end ())); + } + + /* do something - if feature (first token in tree) is in fact enabled, + * make tokens listed afterwards into attributes. i.e.: for + * [cfg_attr(feature = "wow", wow1, wow2)], if "wow" is true, then add + * attributes [wow1] and [wow2] to attribute list. This can also be + * recursive, so check for expanded attributes being recursive and + * possibly recursively call the expand_attrs? */ + } + else + { + i++; + } + } + attrs.shrink_to_fit (); +} + +void +MacroExpander::expand_crate () +{ + NodeId scope_node_id = crate.get_node_id (); + resolver->get_macro_scope ().push (scope_node_id); + + /* fill macro/decorator map from init list? not sure where init list comes + * from? */ + + // TODO: does cfg apply for inner attributes? research. + // the apparent answer (from playground test) is yes + + // expand crate cfg_attr attributes + expand_cfg_attrs (crate.inner_attrs); + + if (fails_cfg_with_expand (crate.inner_attrs)) + { + // basically, delete whole crate + crate.strip_crate (); + // TODO: maybe create warning here? probably not desired behaviour + } + // expand module attributes? + + push_context (ITEM); + + // expand attributes recursively and strip items if required + AttrVisitor attr_visitor (*this); + auto &items = crate.items; + for (auto it = items.begin (); it != items.end ();) + { + auto &item = *it; + + // mark for stripping if required + item->accept_vis (attr_visitor); + + auto fragment = take_expanded_fragment (attr_visitor); + if (fragment.should_expand ()) + { + // Remove the current expanded invocation + it = items.erase (it); + for (auto &node : fragment.get_nodes ()) + { + it = items.insert (it, node.take_item ()); + it++; + } + } + else if (item->is_marked_for_strip ()) + it = items.erase (it); + else + it++; + } + + pop_context (); + + // TODO: should recursive attribute and macro expansion be done in the same + // transversal? Or in separate ones like currently? + + // expand module tree recursively + + // post-process + + // extract exported macros? +} + +bool +MacroExpander::depth_exceeds_recursion_limit () const +{ + return expansion_depth >= cfg.recursion_limit; +} + +bool +MacroExpander::try_match_rule (AST::MacroRule &match_rule, + AST::DelimTokenTree &invoc_token_tree) +{ + MacroInvocLexer lex (invoc_token_tree.to_token_stream ()); + Parser parser (lex); + + AST::MacroMatcher &matcher = match_rule.get_matcher (); + + expansion_depth++; + if (!match_matcher (parser, matcher)) + { + expansion_depth--; + return false; + } + expansion_depth--; + + bool used_all_input_tokens = parser.skip_token (END_OF_FILE); + return used_all_input_tokens; +} + +bool +MacroExpander::match_fragment (Parser &parser, + AST::MacroMatchFragment &fragment) +{ + switch (fragment.get_frag_spec ().get_kind ()) + { + case AST::MacroFragSpec::EXPR: + parser.parse_expr (); + break; + + case AST::MacroFragSpec::BLOCK: + parser.parse_block_expr (); + break; + + case AST::MacroFragSpec::IDENT: + parser.parse_identifier_pattern (); + break; + + case AST::MacroFragSpec::LITERAL: + parser.parse_literal_expr (); + break; + + case AST::MacroFragSpec::ITEM: + parser.parse_item (false); + break; + + case AST::MacroFragSpec::TY: + parser.parse_type (); + break; + + case AST::MacroFragSpec::PAT: + parser.parse_pattern (); + break; + + case AST::MacroFragSpec::PATH: + parser.parse_path_in_expression (); + break; + + case AST::MacroFragSpec::VIS: + parser.parse_visibility (); + break; + + case AST::MacroFragSpec::STMT: { + auto restrictions = ParseRestrictions (); + restrictions.consume_semi = false; + parser.parse_stmt (restrictions); + break; + } + + case AST::MacroFragSpec::LIFETIME: + parser.parse_lifetime_params (); + break; + + // is meta attributes? + case AST::MacroFragSpec::META: + parser.parse_attribute_body (); + break; + + case AST::MacroFragSpec::TT: + parser.parse_token_tree (); + break; + + // i guess we just ignore invalid and just error out + case AST::MacroFragSpec::INVALID: + return false; + } + + // it matches if the parser did not produce errors trying to parse that type + // of item + return !parser.has_errors (); +} + +bool +MacroExpander::match_matcher (Parser &parser, + AST::MacroMatcher &matcher) +{ + if (depth_exceeds_recursion_limit ()) + { + rust_error_at (matcher.get_match_locus (), "reached recursion limit"); + return false; + } + + auto delimiter = parser.peek_current_token (); + + // this is used so we can check that we delimit the stream correctly. + switch (delimiter->get_id ()) + { + case LEFT_PAREN: { + if (!parser.skip_token (LEFT_PAREN)) + return false; + } + break; + + case LEFT_SQUARE: { + if (!parser.skip_token (LEFT_SQUARE)) + return false; + } + break; + + case LEFT_CURLY: { + if (!parser.skip_token (LEFT_CURLY)) + return false; + } + break; + default: + gcc_unreachable (); + } + + const MacroInvocLexer &source = parser.get_token_source (); + + for (auto &match : matcher.get_matches ()) + { + size_t offs_begin = source.get_offs (); + + switch (match->get_macro_match_type ()) + { + case AST::MacroMatch::MacroMatchType::Fragment: { + AST::MacroMatchFragment *fragment + = static_cast (match.get ()); + if (!match_fragment (parser, *fragment)) + return false; + + // matched fragment get the offset in the token stream + size_t offs_end = source.get_offs (); + sub_stack.insert_metavar ( + MatchedFragment (fragment->get_ident (), offs_begin, offs_end)); + } + break; + + case AST::MacroMatch::MacroMatchType::Tok: { + AST::Token *tok = static_cast (match.get ()); + if (!match_token (parser, *tok)) + return false; + } + break; + + case AST::MacroMatch::MacroMatchType::Repetition: { + AST::MacroMatchRepetition *rep + = static_cast (match.get ()); + if (!match_repetition (parser, *rep)) + return false; + } + break; + + case AST::MacroMatch::MacroMatchType::Matcher: { + AST::MacroMatcher *m + = static_cast (match.get ()); + expansion_depth++; + if (!match_matcher (parser, *m)) + { + expansion_depth--; + return false; + } + expansion_depth--; + } + break; + } + } + + switch (delimiter->get_id ()) + { + case LEFT_PAREN: { + if (!parser.skip_token (RIGHT_PAREN)) + return false; + } + break; + + case LEFT_SQUARE: { + if (!parser.skip_token (RIGHT_SQUARE)) + return false; + } + break; + + case LEFT_CURLY: { + if (!parser.skip_token (RIGHT_CURLY)) + return false; + } + break; + default: + gcc_unreachable (); + } + + return true; +} + +bool +MacroExpander::match_token (Parser &parser, AST::Token &token) +{ + // FIXME this needs to actually match the content and the type + return parser.skip_token (token.get_id ()); +} + +bool +MacroExpander::match_n_matches (Parser &parser, + AST::MacroMatchRepetition &rep, + size_t &match_amount, size_t lo_bound, + size_t hi_bound) +{ + match_amount = 0; + auto &matches = rep.get_matches (); + + const MacroInvocLexer &source = parser.get_token_source (); + while (true) + { + // If the current token is a closing macro delimiter, break away. + // TODO: Is this correct? + auto t_id = parser.peek_current_token ()->get_id (); + if (t_id == RIGHT_PAREN || t_id == RIGHT_SQUARE || t_id == RIGHT_CURLY) + break; + + // Skip parsing a separator on the first match, otherwise consume it. + // If it isn't present, this is an error + if (rep.has_sep () && match_amount > 0) + if (!match_token (parser, *rep.get_sep ())) + break; + + bool valid_current_match = false; + for (auto &match : matches) + { + size_t offs_begin = source.get_offs (); + switch (match->get_macro_match_type ()) + { + case AST::MacroMatch::MacroMatchType::Fragment: { + AST::MacroMatchFragment *fragment + = static_cast (match.get ()); + valid_current_match = match_fragment (parser, *fragment); + + // matched fragment get the offset in the token stream + size_t offs_end = source.get_offs (); + + // The main difference with match_matcher happens here: Instead + // of inserting a new fragment, we append to one. If that + // fragment does not exist, then the operation is similar to + // `insert_fragment` with the difference that we are not + // creating a metavariable, but a repetition of one, which is + // really different. + sub_stack.append_fragment ( + MatchedFragment (fragment->get_ident (), offs_begin, + offs_end)); + } + break; + + case AST::MacroMatch::MacroMatchType::Tok: { + AST::Token *tok = static_cast (match.get ()); + valid_current_match = match_token (parser, *tok); + } + break; + + case AST::MacroMatch::MacroMatchType::Repetition: { + AST::MacroMatchRepetition *rep + = static_cast (match.get ()); + valid_current_match = match_repetition (parser, *rep); + } + break; + + case AST::MacroMatch::MacroMatchType::Matcher: { + AST::MacroMatcher *m + = static_cast (match.get ()); + valid_current_match = match_matcher (parser, *m); + } + break; + } + } + // If we've encountered an error once, stop trying to match more + // repetitions + if (!valid_current_match) + break; + + match_amount++; + + // Break early if we notice there's too many expressions already + if (hi_bound && match_amount > hi_bound) + break; + } + + // Check if the amount of matches we got is valid: Is it more than the lower + // bound and less than the higher bound? + bool did_meet_lo_bound = match_amount >= lo_bound; + bool did_meet_hi_bound = hi_bound ? match_amount <= hi_bound : true; + + // If the end-result is valid, then we can clear the parse errors: Since + // repetitions are parsed eagerly, it is okay to fail in some cases + auto res = did_meet_lo_bound && did_meet_hi_bound; + if (res) + parser.clear_errors (); + + return res; +} + +bool +MacroExpander::match_repetition (Parser &parser, + AST::MacroMatchRepetition &rep) +{ + size_t match_amount = 0; + bool res = false; + + std::string lo_str; + std::string hi_str; + switch (rep.get_op ()) + { + case AST::MacroMatchRepetition::MacroRepOp::ANY: + lo_str = "0"; + hi_str = "+inf"; + res = match_n_matches (parser, rep, match_amount); + break; + case AST::MacroMatchRepetition::MacroRepOp::ONE_OR_MORE: + lo_str = "1"; + hi_str = "+inf"; + res = match_n_matches (parser, rep, match_amount, 1); + break; + case AST::MacroMatchRepetition::MacroRepOp::ZERO_OR_ONE: + lo_str = "0"; + hi_str = "1"; + res = match_n_matches (parser, rep, match_amount, 0, 1); + break; + default: + gcc_unreachable (); + } + + if (!res) + rust_error_at (rep.get_match_locus (), + "invalid amount of matches for macro invocation. Expected " + "between %s and %s, got %lu", + lo_str.c_str (), hi_str.c_str (), + (unsigned long) match_amount); + + rust_debug_loc (rep.get_match_locus (), "%s matched %lu times", + res ? "successfully" : "unsuccessfully", + (unsigned long) match_amount); + + // We have to handle zero fragments differently: They will not have been + // "matched" but they are still valid and should be inserted as a special + // case. So we go through the stack map, and for every fragment which doesn't + // exist, insert a zero-matched fragment. + auto &stack_map = sub_stack.peek (); + for (auto &match : rep.get_matches ()) + { + if (match->get_macro_match_type () + == AST::MacroMatch::MacroMatchType::Fragment) + { + auto fragment = static_cast (match.get ()); + auto it = stack_map.find (fragment->get_ident ()); + + if (it == stack_map.end ()) + sub_stack.insert_matches (fragment->get_ident (), + MatchedFragmentContainer::zero ()); + } + } + + return res; +} + +/** + * Helper function to refactor calling a parsing function 0 or more times + */ +static AST::ASTFragment +parse_many (Parser &parser, TokenId &delimiter, + std::function parse_fn) +{ + std::vector nodes; + while (true) + { + if (parser.peek_current_token ()->get_id () == delimiter) + break; + + auto node = parse_fn (); + nodes.emplace_back (std::move (node)); + } + + return AST::ASTFragment (std::move (nodes)); +} + +/** + * Transcribe 0 or more items from a macro invocation + * + * @param parser Parser to extract items from + * @param delimiter Id of the token on which parsing should stop + */ +static AST::ASTFragment +transcribe_many_items (Parser &parser, TokenId &delimiter) +{ + return parse_many (parser, delimiter, [&parser] () { + auto item = parser.parse_item (true); + return AST::SingleASTNode (std::move (item)); + }); +} + +/** + * Transcribe 0 or more external items from a macro invocation + * + * @param parser Parser to extract items from + * @param delimiter Id of the token on which parsing should stop + */ +static AST::ASTFragment +transcribe_many_ext (Parser &parser, TokenId &delimiter) +{ + return parse_many (parser, delimiter, [&parser] () { + auto item = parser.parse_external_item (); + return AST::SingleASTNode (std::move (item)); + }); +} + +/** + * Transcribe 0 or more trait items from a macro invocation + * + * @param parser Parser to extract items from + * @param delimiter Id of the token on which parsing should stop + */ +static AST::ASTFragment +transcribe_many_trait_items (Parser &parser, + TokenId &delimiter) +{ + return parse_many (parser, delimiter, [&parser] () { + auto item = parser.parse_trait_item (); + return AST::SingleASTNode (std::move (item)); + }); +} + +/** + * Transcribe 0 or more impl items from a macro invocation + * + * @param parser Parser to extract items from + * @param delimiter Id of the token on which parsing should stop + */ +static AST::ASTFragment +transcribe_many_impl_items (Parser &parser, TokenId &delimiter) +{ + return parse_many (parser, delimiter, [&parser] () { + auto item = parser.parse_inherent_impl_item (); + return AST::SingleASTNode (std::move (item)); + }); +} + +/** + * Transcribe 0 or more trait impl items from a macro invocation + * + * @param parser Parser to extract items from + * @param delimiter Id of the token on which parsing should stop + */ +static AST::ASTFragment +transcribe_many_trait_impl_items (Parser &parser, + TokenId &delimiter) +{ + return parse_many (parser, delimiter, [&parser] () { + auto item = parser.parse_trait_impl_item (); + return AST::SingleASTNode (std::move (item)); + }); +} + +/** + * Transcribe 0 or more statements from a macro invocation + * + * @param parser Parser to extract statements from + * @param delimiter Id of the token on which parsing should stop + */ +static AST::ASTFragment +transcribe_many_stmts (Parser &parser, TokenId &delimiter) +{ + auto restrictions = ParseRestrictions (); + restrictions.consume_semi = false; + + // FIXME: This is invalid! It needs to also handle cases where the macro + // transcriber is an expression, but since the macro call is followed by + // a semicolon, it's a valid ExprStmt + return parse_many (parser, delimiter, [&parser, restrictions] () { + auto stmt = parser.parse_stmt (restrictions); + return AST::SingleASTNode (std::move (stmt)); + }); +} + +/** + * Transcribe one expression from a macro invocation + * + * @param parser Parser to extract statements from + */ +static AST::ASTFragment +transcribe_expression (Parser &parser) +{ + auto expr = parser.parse_expr (); + + return AST::ASTFragment ({std::move (expr)}); +} + +/** + * Transcribe one type from a macro invocation + * + * @param parser Parser to extract statements from + */ +static AST::ASTFragment +transcribe_type (Parser &parser) +{ + auto type = parser.parse_type (); + + return AST::ASTFragment ({std::move (type)}); +} + +static AST::ASTFragment +transcribe_on_delimiter (Parser &parser, bool semicolon, + AST::DelimType delimiter, TokenId last_token_id) +{ + if (semicolon || delimiter == AST::DelimType::CURLY) + return transcribe_many_stmts (parser, last_token_id); + else + return transcribe_expression (parser); +} // namespace Rust + +static AST::ASTFragment +transcribe_context (MacroExpander::ContextType ctx, + Parser &parser, bool semicolon, + AST::DelimType delimiter, TokenId last_token_id) +{ + // The flow-chart in order to choose a parsing function is as follows: + // + // [switch special context] + // -- Item --> parser.parse_item(); + // -- Trait --> parser.parse_trait_item(); + // -- Impl --> parser.parse_impl_item(); + // -- Extern --> parser.parse_extern_item(); + // -- None --> [has semicolon?] + // -- Yes --> parser.parse_stmt(); + // -- No --> [switch invocation.delimiter()] + // -- { } --> parser.parse_stmt(); + // -- _ --> parser.parse_expr(); // once! + + // If there is a semicolon OR we are expanding a MacroInvocationSemi, then + // we can parse multiple items. Otherwise, parse *one* expression + + switch (ctx) + { + case MacroExpander::ContextType::ITEM: + return transcribe_many_items (parser, last_token_id); + break; + case MacroExpander::ContextType::TRAIT: + return transcribe_many_trait_items (parser, last_token_id); + break; + case MacroExpander::ContextType::IMPL: + return transcribe_many_impl_items (parser, last_token_id); + break; + case MacroExpander::ContextType::TRAIT_IMPL: + return transcribe_many_trait_impl_items (parser, last_token_id); + break; + case MacroExpander::ContextType::EXTERN: + return transcribe_many_ext (parser, last_token_id); + break; + case MacroExpander::ContextType::TYPE: + return transcribe_type (parser); + break; + default: + return transcribe_on_delimiter (parser, semicolon, delimiter, + last_token_id); + } +} + +static std::string +tokens_to_str (std::vector> &tokens) +{ + std::string str; + if (!tokens.empty ()) + { + str += tokens[0]->as_string (); + for (size_t i = 1; i < tokens.size (); i++) + str += " " + tokens[i]->as_string (); + } + + return str; +} + +AST::ASTFragment +MacroExpander::transcribe_rule ( + AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree, + std::map &matched_fragments, + bool semicolon, ContextType ctx) +{ + // we can manipulate the token tree to substitute the dollar identifiers so + // that when we call parse its already substituted for us + AST::MacroTranscriber &transcriber = match_rule.get_transcriber (); + AST::DelimTokenTree &transcribe_tree = transcriber.get_token_tree (); + + auto invoc_stream = invoc_token_tree.to_token_stream (); + auto macro_rule_tokens = transcribe_tree.to_token_stream (); + + auto substitute_context + = SubstituteCtx (invoc_stream, macro_rule_tokens, matched_fragments); + std::vector> substituted_tokens + = substitute_context.substitute_tokens (); + + rust_debug ("substituted tokens: %s", + tokens_to_str (substituted_tokens).c_str ()); + + // parse it to an ASTFragment + MacroInvocLexer lex (std::move (substituted_tokens)); + Parser parser (lex); + + auto last_token_id = TokenId::RIGHT_CURLY; + + // this is used so we can check that we delimit the stream correctly. + switch (transcribe_tree.get_delim_type ()) + { + case AST::DelimType::PARENS: + last_token_id = TokenId::RIGHT_PAREN; + rust_assert (parser.skip_token (LEFT_PAREN)); + break; + + case AST::DelimType::CURLY: + rust_assert (parser.skip_token (LEFT_CURLY)); + break; + + case AST::DelimType::SQUARE: + last_token_id = TokenId::RIGHT_SQUARE; + rust_assert (parser.skip_token (LEFT_SQUARE)); + break; + } + + // see https://github.com/Rust-GCC/gccrs/issues/22 + // TL;DR: + // - Treat all macro invocations with parentheses, (), or square brackets, + // [], as expressions. + // - If the macro invocation has curly brackets, {}, it may be parsed as a + // statement depending on the context. + // - If the macro invocation has a semicolon at the end, it must be parsed + // as a statement (either via ExpressionStatement or + // MacroInvocationWithSemi) + + auto fragment + = transcribe_context (ctx, parser, semicolon, + invoc_token_tree.get_delim_type (), last_token_id); + + // emit any errors + if (parser.has_errors ()) + { + for (auto &err : parser.get_errors ()) + rust_error_at (err.locus, "%s", err.message.c_str ()); + return AST::ASTFragment::create_error (); + } + + // are all the tokens used? + bool did_delimit = parser.skip_token (last_token_id); + + bool reached_end_of_stream = did_delimit && parser.skip_token (END_OF_FILE); + if (!reached_end_of_stream) + { + const_TokenPtr current_token = parser.peek_current_token (); + rust_error_at (current_token->get_locus (), + "tokens here and after are unparsed"); + } + + return fragment; +} +} // namespace Rust diff --git a/gcc/rust/expand/rust-macro-expand.h b/gcc/rust/expand/rust-macro-expand.h new file mode 100644 index 00000000000..94d6702ecb8 --- /dev/null +++ b/gcc/rust/expand/rust-macro-expand.h @@ -0,0 +1,366 @@ +// 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_MACRO_EXPAND_H +#define RUST_MACRO_EXPAND_H + +#include "rust-buffered-queue.h" +#include "rust-parse.h" +#include "rust-token.h" +#include "rust-ast.h" +#include "rust-macro.h" +#include "rust-hir-map.h" +#include "rust-name-resolver.h" +#include "rust-macro-invoc-lexer.h" + +// Provides objects and method prototypes for macro expansion + +namespace Rust { +// forward decls for AST +namespace AST { +class MacroInvocation; +} + +// Object used to store configuration data for macro expansion. +// NOTE: Keep all these items complying with the latest rustc. +struct ExpansionCfg +{ + // features? + // TODO: Add `features' when we have it. + unsigned int recursion_limit = 1024; + bool trace_mac = false; // trace macro + bool should_test = false; // strip #[test] nodes if false + bool keep_macs = false; // keep macro definitions + std::string crate_name = ""; +}; + +struct MatchedFragment +{ + std::string fragment_ident; + size_t token_offset_begin; + size_t token_offset_end; + + MatchedFragment (std::string identifier, size_t token_offset_begin, + size_t token_offset_end) + : fragment_ident (identifier), token_offset_begin (token_offset_begin), + token_offset_end (token_offset_end) + {} + + /** + * Empty constructor for uninitialized fragments + */ + MatchedFragment () : MatchedFragment ("", 0, 0) {} + + std::string as_string () const + { + return fragment_ident + "=" + std::to_string (token_offset_begin) + ":" + + std::to_string (token_offset_end); + } +}; + +class MatchedFragmentContainer +{ +public: + // Does the container refer to a simple metavariable, different from a + // repetition repeated once + enum class Kind + { + MetaVar, + Repetition, + }; + + MatchedFragmentContainer (std::vector fragments, + Kind kind = Kind::Repetition) + : fragments (fragments), kind (kind) + {} + + /** + * Create a valid fragment matched zero times. This is useful for repetitions + * which allow the absence of a fragment, such as * and ? + */ + static MatchedFragmentContainer zero () + { + return MatchedFragmentContainer ({}); + } + + /** + * Create a valid fragment matched one time + */ + static MatchedFragmentContainer metavar (MatchedFragment fragment) + { + return MatchedFragmentContainer ({fragment}, Kind::MetaVar); + } + + /** + * Add a matched fragment to the container + */ + void add_fragment (MatchedFragment fragment) + { + rust_assert (!is_single_fragment ()); + + fragments.emplace_back (fragment); + } + + size_t get_match_amount () const { return fragments.size (); } + const std::vector &get_fragments () const + { + return fragments; + } + // const std::string &get_fragment_name () const { return fragment_name; } + + bool is_single_fragment () const + { + return get_match_amount () == 1 && kind == Kind::MetaVar; + } + + const MatchedFragment get_single_fragment () const + { + rust_assert (is_single_fragment ()); + + return fragments[0]; + } + + const Kind &get_kind () const { return kind; } + +private: + /** + * Fragments matched `match_amount` times. This can be an empty vector + * in case having zero matches is allowed (i.e ? or * operators) + */ + std::vector fragments; + Kind kind; +}; + +class SubstitutionScope +{ +public: + SubstitutionScope () : stack () {} + + void push () { stack.push_back ({}); } + + std::map pop () + { + auto top = stack.back (); + stack.pop_back (); + return top; + } + + std::map &peek () + { + return stack.back (); + } + + /** + * Insert a new matched metavar into the current substitution map + */ + void insert_metavar (MatchedFragment fragment) + { + auto ¤t_map = stack.back (); + auto it = current_map.find (fragment.fragment_ident); + + if (it == current_map.end ()) + current_map.insert ({fragment.fragment_ident, + MatchedFragmentContainer::metavar (fragment)}); + else + gcc_unreachable (); + } + + /** + * Append a new matched fragment to a repetition into the current substitution + * map + */ + void append_fragment (MatchedFragment fragment) + { + auto ¤t_map = stack.back (); + auto it = current_map.find (fragment.fragment_ident); + + if (it == current_map.end ()) + current_map.insert ( + {fragment.fragment_ident, MatchedFragmentContainer ({fragment})}); + else + it->second.add_fragment (fragment); + } + + void insert_matches (std::string key, MatchedFragmentContainer matches) + { + auto ¤t_map = stack.back (); + auto it = current_map.find (key); + rust_assert (it == current_map.end ()); + + current_map.insert ({key, matches}); + } + +private: + std::vector> stack; +}; + +// Object used to store shared data (between functions) for macro expansion. +struct MacroExpander +{ + enum ContextType + { + ITEM, + BLOCK, + EXTERN, + TYPE, + TRAIT, + IMPL, + TRAIT_IMPL, + }; + + ExpansionCfg cfg; + unsigned int expansion_depth = 0; + + MacroExpander (AST::Crate &crate, ExpansionCfg cfg, Session &session) + : cfg (cfg), crate (crate), session (session), + sub_stack (SubstitutionScope ()), + expanded_fragment (AST::ASTFragment::create_error ()), + resolver (Resolver::Resolver::get ()), + mappings (Analysis::Mappings::get ()) + {} + + ~MacroExpander () = default; + + // Expands all macros in the crate passed in. + void expand_crate (); + + /* Expands a macro invocation - possibly make both + * have similar duck-typed interface and use templates?*/ + // should this be public or private? + void expand_invoc (AST::MacroInvocation &invoc, bool has_semicolon); + + // Expands a single declarative macro. + AST::ASTFragment expand_decl_macro (Location locus, + AST::MacroInvocData &invoc, + AST::MacroRulesDefinition &rules_def, + bool semicolon); + + void expand_cfg_attrs (AST::AttrVec &attrs); + bool fails_cfg (const AST::AttrVec &attr) const; + bool fails_cfg_with_expand (AST::AttrVec &attrs) const; + + bool depth_exceeds_recursion_limit () const; + + bool try_match_rule (AST::MacroRule &match_rule, + AST::DelimTokenTree &invoc_token_tree); + + AST::ASTFragment transcribe_rule ( + AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree, + std::map &matched_fragments, + bool semicolon, ContextType ctx); + + bool match_fragment (Parser &parser, + AST::MacroMatchFragment &fragment); + + bool match_token (Parser &parser, AST::Token &token); + + bool match_repetition (Parser &parser, + AST::MacroMatchRepetition &rep); + + bool match_matcher (Parser &parser, + AST::MacroMatcher &matcher); + + /** + * Match any amount of matches + * + * @param parser Parser to use for matching + * @param rep Repetition to try and match + * @param match_amount Reference in which to store the ammount of succesful + * and valid matches + * + * @param lo_bound Lower bound of the matcher. When specified, the matcher + * will only succeed if it parses at *least* `lo_bound` fragments. If + * unspecified, the matcher could succeed when parsing 0 fragments. + * + * @param hi_bound Higher bound of the matcher. When specified, the matcher + * will only succeed if it parses *less than* `hi_bound` fragments. If + * unspecified, the matcher could succeed when parsing an infinity of + * fragments. + * + * @return true if matching was successful and within the given limits, false + * otherwise + */ + bool match_n_matches (Parser &parser, + AST::MacroMatchRepetition &rep, size_t &match_amount, + size_t lo_bound = 0, size_t hi_bound = 0); + + void push_context (ContextType t) { context.push_back (t); } + + ContextType pop_context () + { + rust_assert (!context.empty ()); + + ContextType t = context.back (); + context.pop_back (); + + return t; + } + + ContextType peek_context () { return context.back (); } + + void set_expanded_fragment (AST::ASTFragment &&fragment) + { + expanded_fragment = std::move (fragment); + } + + AST::ASTFragment take_expanded_fragment (AST::ASTVisitor &vis) + { + AST::ASTFragment old_fragment = std::move (expanded_fragment); + auto accumulator = std::vector (); + expanded_fragment = AST::ASTFragment::create_error (); + + for (auto &node : old_fragment.get_nodes ()) + { + expansion_depth++; + node.accept_vis (vis); + // we'll decide the next move according to the outcome of the macro + // expansion + if (expanded_fragment.is_error ()) + accumulator.push_back (node); // if expansion fails, there might be a + // non-macro expression we need to keep + else + { + // if expansion succeeded, then we need to merge the fragment with + // the contents in the accumulator, so that our final expansion + // result will contain non-macro nodes as it should + auto new_nodes = expanded_fragment.get_nodes (); + std::move (new_nodes.begin (), new_nodes.end (), + std::back_inserter (accumulator)); + expanded_fragment = AST::ASTFragment (accumulator); + } + expansion_depth--; + } + + return old_fragment; + } + +private: + AST::Crate &crate; + Session &session; + SubstitutionScope sub_stack; + std::vector context; + AST::ASTFragment expanded_fragment; + +public: + Resolver::Resolver *resolver; + Analysis::Mappings *mappings; +}; + +} // namespace Rust + +#endif diff --git a/gcc/rust/expand/rust-macro-invoc-lexer.cc b/gcc/rust/expand/rust-macro-invoc-lexer.cc new file mode 100644 index 00000000000..8a43d29e0d1 --- /dev/null +++ b/gcc/rust/expand/rust-macro-invoc-lexer.cc @@ -0,0 +1,29 @@ +#include "rust-macro-invoc-lexer.h" + +namespace Rust { + +const_TokenPtr +MacroInvocLexer::peek_token (int n) +{ + if ((offs + n) >= token_stream.size ()) + return Token::make (END_OF_FILE, Location ()); + + return token_stream.at (offs + n)->get_tok_ptr (); +} + +// Advances current token to n + 1 tokens ahead of current position. +void +MacroInvocLexer::skip_token (int n) +{ + offs += (n + 1); +} + +void +MacroInvocLexer::split_current_token (TokenId new_left __attribute__ ((unused)), + TokenId new_right + __attribute__ ((unused))) +{ + // FIXME + gcc_unreachable (); +} +} // namespace Rust diff --git a/gcc/rust/expand/rust-macro-invoc-lexer.h b/gcc/rust/expand/rust-macro-invoc-lexer.h new file mode 100644 index 00000000000..0fd4554d02f --- /dev/null +++ b/gcc/rust/expand/rust-macro-invoc-lexer.h @@ -0,0 +1,64 @@ +// 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_MACRO_INVOC_LEXER_H +#define RUST_MACRO_INVOC_LEXER_H + +#include "rust-ast.h" + +namespace Rust { +class MacroInvocLexer +{ +public: + MacroInvocLexer (std::vector> stream) + : offs (0), token_stream (std::move (stream)) + {} + + // Returns token n tokens ahead of current position. + const_TokenPtr peek_token (int n); + + // Peeks the current token. + const_TokenPtr peek_token () { return peek_token (0); } + + // Advances current token to n + 1 tokens ahead of current position. + void skip_token (int n); + + // Skips the current token. + void skip_token () { skip_token (0); } + + // Splits the current token into two. Intended for use with nested generics + // closes (i.e. T> where >> is wrongly lexed as one token). Note that + // this will only work with "simple" tokens like punctuation. + void split_current_token (TokenId new_left, TokenId new_right); + + std::string get_filename () const + { + // FIXME + gcc_unreachable (); + return "FIXME"; + } + + size_t get_offs () const { return offs; } + +private: + size_t offs; + std::vector> token_stream; +}; +} // namespace Rust + +#endif // RUST_MACRO_INVOC_LEXER_H diff --git a/gcc/rust/expand/rust-macro-substitute-ctx.cc b/gcc/rust/expand/rust-macro-substitute-ctx.cc new file mode 100644 index 00000000000..9592d2d2a9e --- /dev/null +++ b/gcc/rust/expand/rust-macro-substitute-ctx.cc @@ -0,0 +1,312 @@ +#include "rust-macro-substitute-ctx.h" + +namespace Rust { + +std::vector> +SubstituteCtx::substitute_metavar (std::unique_ptr &metavar) +{ + auto metavar_name = metavar->get_str (); + + std::vector> expanded; + auto it = fragments.find (metavar_name); + if (it == fragments.end ()) + { + // Return a copy of the original token + expanded.push_back (metavar->clone_token ()); + } + else + { + // If we are expanding a metavar which has a lof of matches, we are + // currently expanding a repetition metavar - not a simple metavar. We + // need to error out and inform the user. + // Associated test case for an example: compile/macro-issue1224.rs + if (it->second.get_match_amount () != 1) + { + rust_error_at (metavar->get_locus (), + "metavariable is still repeating at this depth"); + rust_inform ( + metavar->get_locus (), + "you probably forgot the repetition operator: %<%s%s%s%>", "$(", + metavar->as_string ().c_str (), ")*"); + return expanded; + } + + // We only care about the vector when expanding repetitions. + // Just access the first element of the vector. + auto &frag = it->second.get_single_fragment (); + for (size_t offs = frag.token_offset_begin; offs < frag.token_offset_end; + offs++) + { + auto &tok = input.at (offs); + expanded.push_back (tok->clone_token ()); + } + } + + return expanded; +} + +bool +SubstituteCtx::check_repetition_amount (size_t pattern_start, + size_t pattern_end, + size_t &expected_repetition_amount) +{ + bool first_fragment_found = false; + bool is_valid = true; + + for (size_t i = pattern_start; i < pattern_end; i++) + { + if (macro.at (i)->get_id () == DOLLAR_SIGN) + { + auto &frag_token = macro.at (i + 1); + if (frag_token->get_id () == IDENTIFIER) + { + auto it = fragments.find (frag_token->get_str ()); + if (it == fragments.end ()) + { + // If the repetition is not anything we know (ie no declared + // metavars, or metavars which aren't present in the + // fragment), we can just error out. No need to paste the + // tokens as if nothing had happened. + rust_error_at (frag_token->get_locus (), + "metavar %s used in repetition does not exist", + frag_token->get_str ().c_str ()); + + is_valid = false; + } + + auto &fragment = it->second; + + size_t repeat_amount = fragment.get_match_amount (); + if (!first_fragment_found) + { + first_fragment_found = true; + expected_repetition_amount = repeat_amount; + } + else + { + if (repeat_amount != expected_repetition_amount + && !fragment.is_single_fragment ()) + { + rust_error_at ( + frag_token->get_locus (), + "different amount of matches used in merged " + "repetitions: expected %lu, got %lu", + (unsigned long) expected_repetition_amount, + (unsigned long) repeat_amount); + is_valid = false; + } + } + } + } + } + + return is_valid; +} + +std::vector> +SubstituteCtx::substitute_repetition ( + size_t pattern_start, size_t pattern_end, + std::unique_ptr separator_token) +{ + rust_assert (pattern_end < macro.size ()); + + size_t repeat_amount = 0; + if (!check_repetition_amount (pattern_start, pattern_end, repeat_amount)) + return {}; + + rust_debug ("repetition amount to use: %lu", (unsigned long) repeat_amount); + std::vector> expanded; + std::vector> new_macro; + + // We want to generate a "new macro" to substitute with. This new macro + // should contain only the tokens inside the pattern + for (size_t tok_idx = pattern_start; tok_idx < pattern_end; tok_idx++) + new_macro.emplace_back (macro.at (tok_idx)->clone_token ()); + + // Then, we want to create a subset of the matches so that + // `substitute_tokens()` can only see one fragment per metavar. Let's say we + // have the following user input: (1 145 'h') + // on the following match arm: ($($lit:literal)*) + // which causes the following matches: { "lit": [1, 145, 'h'] } + // + // The pattern (new_macro) is `$lit:literal` + // The first time we expand it, we want $lit to have the following token: 1 + // The second time, 145 + // The third and final time, 'h' + // + // In order to do so we must create "sub maps", which only contain parts of + // the original matches + // sub-maps: [ { "lit": 1 }, { "lit": 145 }, { "lit": 'h' } ] + // + // and give them to `substitute_tokens` one by one. + + for (size_t i = 0; i < repeat_amount; i++) + { + std::map sub_map; + for (auto &kv_match : fragments) + { + MatchedFragment sub_fragment; + + // FIXME: Hack: If a fragment is not repeated, how does it fit in the + // submap? Do we really want to expand it? Is this normal behavior? + if (kv_match.second.is_single_fragment ()) + sub_fragment = kv_match.second.get_single_fragment (); + else + sub_fragment = kv_match.second.get_fragments ()[i]; + + sub_map.insert ( + {kv_match.first, MatchedFragmentContainer::metavar (sub_fragment)}); + } + + auto substitute_context = SubstituteCtx (input, new_macro, sub_map); + auto new_tokens = substitute_context.substitute_tokens (); + + // Skip the first repetition, but add the separator to the expanded + // tokens if it is present + if (i != 0 && separator_token) + expanded.emplace_back (separator_token->clone_token ()); + + for (auto &new_token : new_tokens) + expanded.emplace_back (new_token->clone_token ()); + } + + // FIXME: We also need to make sure that all subsequent fragments + // contain the same amount of repetitions as the first one + + return expanded; +} + +static bool +is_rep_op (std::unique_ptr &tok) +{ + auto id = tok->get_id (); + return id == QUESTION_MARK || id == ASTERISK || id == PLUS; +} + +std::pair>, size_t> +SubstituteCtx::substitute_token (size_t token_idx) +{ + auto &token = macro.at (token_idx); + switch (token->get_id ()) + { + case IDENTIFIER: + rust_debug ("expanding metavar: %s", token->get_str ().c_str ()); + return {substitute_metavar (token), 1}; + case LEFT_PAREN: { + // We need to parse up until the closing delimiter and expand this + // fragment->n times. + rust_debug ("expanding repetition"); + + // We're in a context where macro repetitions have already been + // parsed and validated: This means that + // 1/ There will be no delimiters as that is an error + // 2/ There are no fragment specifiers anymore, which prevents us + // from reusing parser functions. + // + // Repetition patterns are also special in that they cannot contain + // "rogue" delimiters: For example, this is invalid, as they are + // parsed as MacroMatches and must contain a correct amount of + // delimiters. + // `$($e:expr ) )` + // ^ rogue closing parenthesis + // + // With all of that in mind, we can simply skip ahead from one + // parenthesis to the other to find the pattern to expand. Of course, + // pairs of delimiters, including parentheses, are allowed. + // `$($e:expr ( ) )` + // Parentheses are the sole delimiter for which we need a special + // behavior since they delimit the repetition pattern + + size_t pattern_start = token_idx + 1; + size_t pattern_end = pattern_start; + auto parentheses_stack = 0; + for (size_t idx = pattern_start; idx < macro.size (); idx++) + { + if (macro.at (idx)->get_id () == LEFT_PAREN) + { + parentheses_stack++; + } + else if (macro.at (idx)->get_id () == RIGHT_PAREN) + { + if (parentheses_stack == 0) + { + pattern_end = idx; + break; + } + parentheses_stack--; + } + } + + // Unreachable case, but let's make sure we don't ever run into it + rust_assert (pattern_end != pattern_start); + + std::unique_ptr separator_token = nullptr; + if (pattern_end + 1 <= macro.size ()) + { + auto &post_pattern_token = macro.at (pattern_end + 1); + if (!is_rep_op (post_pattern_token)) + separator_token = post_pattern_token->clone_token (); + } + + // Amount of tokens to skip + auto to_skip = 0; + // Parentheses + to_skip += 2; + // Repetition operator + to_skip += 1; + // Separator + if (separator_token) + to_skip += 1; + + return {substitute_repetition (pattern_start, pattern_end, + std::move (separator_token)), + pattern_end - pattern_start + to_skip}; + } + // TODO: We need to check if the $ was alone. In that case, do + // not error out: Simply act as if there was an empty identifier + // with no associated fragment and paste the dollar sign in the + // transcription. Unsure how to do that since we always have at + // least the closing curly brace after an empty $... + default: + rust_error_at (token->get_locus (), + "unexpected token in macro transcribe: expected " + "%<(%> or identifier after %<$%>, got %<%s%>", + get_token_description (token->get_id ())); + } + + // FIXME: gcc_unreachable() error case? + return {std::vector> (), 0}; +} + +std::vector> +SubstituteCtx::substitute_tokens () +{ + std::vector> replaced_tokens; + rust_debug ("expanding tokens"); + + for (size_t i = 0; i < macro.size (); i++) + { + auto &tok = macro.at (i); + if (tok->get_id () == DOLLAR_SIGN) + { + // Aaaaah, if only we had C++17 :) + // auto [expanded, tok_to_skip] = ... + auto p = substitute_token (i + 1); + auto expanded = std::move (p.first); + auto tok_to_skip = p.second; + + i += tok_to_skip; + + for (auto &token : expanded) + replaced_tokens.emplace_back (token->clone_token ()); + } + else + { + replaced_tokens.emplace_back (tok->clone_token ()); + } + } + + return replaced_tokens; +} + +} // namespace Rust diff --git a/gcc/rust/expand/rust-macro-substitute-ctx.h b/gcc/rust/expand/rust-macro-substitute-ctx.h new file mode 100644 index 00000000000..81dcab7643b --- /dev/null +++ b/gcc/rust/expand/rust-macro-substitute-ctx.h @@ -0,0 +1,93 @@ +// 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 +// . + +#include "rust-ast.h" +#include "rust-macro-expand.h" + +namespace Rust { +class SubstituteCtx +{ + std::vector> &input; + std::vector> ¯o; + std::map &fragments; + + /** + * Find the repetition amount to use when expanding a repetition, and + * check that all fragments used respect that repetition amount + * + * @param pattern_start Start of the repetition pattern + * @param pattern_end End of the repetition pattern + * @param repeat_amount Reference to fill with the matched repetition amount + */ + bool check_repetition_amount (size_t pattern_start, size_t pattern_end, + size_t &repeat_amount); + +public: + SubstituteCtx (std::vector> &input, + std::vector> ¯o, + std::map &fragments) + : input (input), macro (macro), fragments (fragments) + {} + + /** + * Substitute a metavariable by its given fragment in a transcribing context, + * i.e. replacing $var with the associated fragment. + * + * @param metavar Metavariable to try and replace + * + * @return A token containing the associated fragment expanded into tokens if + * any, or the cloned token if no fragment was associated + */ + std::vector> + substitute_metavar (std::unique_ptr &metavar); + + /** + * Substitute a macro repetition by its given fragments + * + * @param pattern_start Start index of the pattern tokens + * @param pattern_end End index of the patterns tokens + * @param separator Optional separator to include when expanding tokens + * + * @return A vector containing the repeated pattern + */ + std::vector> + substitute_repetition (size_t pattern_start, size_t pattern_end, + std::unique_ptr separator); + + /** + * Substitute a given token by its appropriate representation + * + * @param token_idx Current token to try and substitute + * + * @return A token containing the associated fragment expanded into tokens if + * any, or the cloned token if no fragment was associated, as well as the + * amount of tokens that should be skipped before the next invocation. Since + * this function may consume more than just one token, it is important to skip + * ahead of the input to avoid mis-substitutions + */ + std::pair>, size_t> + substitute_token (size_t token_idx); + + /** + * Substitute all tokens by their appropriate representation + * + * @return A vector containing the substituted tokens + */ + std::vector> substitute_tokens (); +}; +} // namespace Rust From patchwork Wed Aug 24 11:59:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56981 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 BD9B0385F015 for ; Wed, 24 Aug 2022 12:01:47 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x436.google.com (mail-wr1-x436.google.com [IPv6:2a00:1450:4864:20::436]) by sourceware.org (Postfix) with ESMTPS id EE1F93836001; Wed, 24 Aug 2022 12:00:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org EE1F93836001 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x436.google.com with SMTP id z16so1689777wrh.10; Wed, 24 Aug 2022 05:00:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=j00CbB+sF54RFCLpvs6CiGkZ25oojrB26ggOqjGu+O8=; b=kFp4hKBevuAytb7uluMT32A4eXnI2oTNNqNZ6z24BC1iVDPWftafI3UaPSqU+Lb0G9 HTqTlJCHY/i9ER2PiadFK7mP0l8K0uk7juJIGTosfFx/8Pe2PPTvT5gxSTZgClFzeLhH R0CeyJi8FCKZ2sYvgvxEFe/NpQhlAVY5vhrQhDzTKaS5LAdqrSQ6MUtsvxYOBz3ywFdr Cd/lG7A2t/xFFnCa9yKdOvcvbLKUUDDOnNOqLnia3KDNUtH/I1F14zCgRMFOitKbgPc3 +k1UxSeG27Rfix7xHN0zbmpAVB9euaui/i5QSw1umz2YzjMDjA/11FdxLDytiGlt2wlI uk2A== 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; bh=j00CbB+sF54RFCLpvs6CiGkZ25oojrB26ggOqjGu+O8=; b=Tknwibt7qMQHupYoHtr4vEpE2XSEOhyqU2Rfgjp1BADV68ftJfkRImRc4zkeneeOfn I7LKazle2YRHoXIA74yOz7cSL2g4syodTt13nhjSgt74OPlfIyVkhJn41UzyEkFN08uk 86a3YJDFB627H8iitq1ApBdhM4ODMvbp3Ac73bsebbIXn//8EWiw6OE5TQeGc6yDk35E BWp4k/com1qR4dd3oSrtOllX1aituuux8zL8eDP/lADzrOFrUdv4D7BAAGqf9WQx0QiU UlscA/1Diaxjf7gQ3wApWcJp7JVC50yRU+8E8ndS9kaR4LLTENcZ7pEPVUrYSC7LaYAt 07VA== X-Gm-Message-State: ACgBeo2yHX0dva3nFNqD8NHekhzlq6qXYXheEsIW6B//e8CPRV/YBeK+ Z1OimuFzYZ5AGKifkZoROJcV8v738zc= X-Google-Smtp-Source: AA6agR7fR5Lowm10iFhvAS2vePqY7imDSciSohTBluyZNVI2gJCyPgcJcwwAqOs0UkQ3T/krtbGQyg== X-Received: by 2002:a05:6000:697:b0:225:30e9:362b with SMTP id bo23-20020a056000069700b0022530e9362bmr15206013wrb.687.1661342444869; Wed, 24 Aug 2022 05:00:44 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:44 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 12/37] gccrs: Add name resolution pass to the Rust front-end Date: Wed, 24 Aug 2022 12:59:31 +0100 Message-Id: <20220824115956.737931-13-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron The name resolution is split into two phases, one toplevel pass which scans the whole "Crate" which iterates all items and nested items in modules to generate a context class full of CanonicalPath items. It also generates a hierarchy of parent->child and child->parent relationships using the AST NodeId for PathResolution in the second phase. The second phase drills into each item like functions and creates a stack of canonical paths for variables etc so that we can store information in a side table of usage variable 'a' resolves to NodeId '123' which refers to the NodeId of the "let a;" statement. --- gcc/rust/resolve/rust-ast-resolve-base.cc | 658 +++++++++ gcc/rust/resolve/rust-ast-resolve-base.h | 221 +++ gcc/rust/resolve/rust-ast-resolve-expr.cc | 574 ++++++++ gcc/rust/resolve/rust-ast-resolve-expr.h | 133 ++ gcc/rust/resolve/rust-ast-resolve-implitem.h | 275 ++++ gcc/rust/resolve/rust-ast-resolve-item.cc | 1237 +++++++++++++++++ gcc/rust/resolve/rust-ast-resolve-item.h | 149 ++ gcc/rust/resolve/rust-ast-resolve-path.cc | 384 +++++ gcc/rust/resolve/rust-ast-resolve-path.h | 52 + gcc/rust/resolve/rust-ast-resolve-pattern.cc | 163 +++ gcc/rust/resolve/rust-ast-resolve-pattern.h | 98 ++ gcc/rust/resolve/rust-ast-resolve-stmt.cc | 38 + gcc/rust/resolve/rust-ast-resolve-stmt.h | 378 +++++ .../rust-ast-resolve-struct-expr-field.cc | 61 + .../rust-ast-resolve-struct-expr-field.h | 55 + gcc/rust/resolve/rust-ast-resolve-toplevel.h | 460 ++++++ gcc/rust/resolve/rust-ast-resolve-type.cc | 582 ++++++++ gcc/rust/resolve/rust-ast-resolve-type.h | 290 ++++ gcc/rust/resolve/rust-ast-resolve.cc | 115 ++ gcc/rust/resolve/rust-ast-resolve.h | 50 + gcc/rust/resolve/rust-ast-verify-assignee.h | 84 ++ gcc/rust/resolve/rust-name-resolver.cc | 503 +++++++ gcc/rust/resolve/rust-name-resolver.h | 212 +++ 23 files changed, 6772 insertions(+) create mode 100644 gcc/rust/resolve/rust-ast-resolve-base.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve-base.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-expr.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve-expr.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-implitem.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-item.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve-item.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-path.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve-path.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-pattern.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve-pattern.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-stmt.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve-stmt.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-struct-expr-field.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve-struct-expr-field.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-toplevel.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-type.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve-type.h create mode 100644 gcc/rust/resolve/rust-ast-resolve.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve.h create mode 100644 gcc/rust/resolve/rust-ast-verify-assignee.h create mode 100644 gcc/rust/resolve/rust-name-resolver.cc create mode 100644 gcc/rust/resolve/rust-name-resolver.h diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc new file mode 100644 index 00000000000..2a78918fbdb --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-base.cc @@ -0,0 +1,658 @@ +// 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 +// . + +#include "rust-ast-resolve-base.h" +#include "rust-ast-resolve-expr.h" +#include "rust-ast-resolve-path.h" +#include "rust-item.h" + +namespace Rust { +namespace Resolver { + +bool +ResolverBase::resolve_visibility (const AST::Visibility &vis) +{ + if (vis.has_path ()) + { + auto path = vis.get_path (); + ResolvePath::go (&path); + + // Do we need to lookup something here? + // Is it just about resolving the names correctly so we can look them up + // later? + } + + return true; +} + +// Default visitors implementations + +void +ResolverBase::visit (AST::Token &) +{} + +void +ResolverBase::visit (AST::DelimTokenTree &) +{} + +void +ResolverBase::visit (AST::AttrInputMetaItemContainer &) +{} + +void +ResolverBase::visit (AST::IdentifierExpr &) +{} + +void +ResolverBase::visit (AST::Lifetime &) +{} + +void +ResolverBase::visit (AST::LifetimeParam &) +{} + +void +ResolverBase::visit (AST::ConstGenericParam &) +{} + +void +ResolverBase::visit (AST::PathInExpression &) +{} + +void +ResolverBase::visit (AST::TypePathSegment &) +{} + +void +ResolverBase::visit (AST::TypePathSegmentGeneric &) +{} + +void +ResolverBase::visit (AST::TypePathSegmentFunction &) +{} + +void +ResolverBase::visit (AST::TypePath &) +{} + +void +ResolverBase::visit (AST::QualifiedPathInExpression &) +{} + +void +ResolverBase::visit (AST::QualifiedPathInType &) +{} + +void +ResolverBase::visit (AST::LiteralExpr &) +{} + +void +ResolverBase::visit (AST::AttrInputLiteral &) +{} + +void +ResolverBase::visit (AST::MetaItemLitExpr &) +{} + +void +ResolverBase::visit (AST::MetaItemPathLit &) +{} + +void +ResolverBase::visit (AST::BorrowExpr &) +{} + +void +ResolverBase::visit (AST::DereferenceExpr &) +{} + +void +ResolverBase::visit (AST::ErrorPropagationExpr &) +{} + +void +ResolverBase::visit (AST::NegationExpr &) +{} + +void +ResolverBase::visit (AST::ArithmeticOrLogicalExpr &) +{} + +void +ResolverBase::visit (AST::ComparisonExpr &) +{} + +void +ResolverBase::visit (AST::LazyBooleanExpr &) +{} + +void +ResolverBase::visit (AST::TypeCastExpr &) +{} + +void +ResolverBase::visit (AST::AssignmentExpr &) +{} + +void +ResolverBase::visit (AST::CompoundAssignmentExpr &) +{} + +void +ResolverBase::visit (AST::GroupedExpr &) +{} + +void +ResolverBase::visit (AST::ArrayElemsValues &) +{} + +void +ResolverBase::visit (AST::ArrayElemsCopied &) +{} + +void +ResolverBase::visit (AST::ArrayExpr &) +{} + +void +ResolverBase::visit (AST::ArrayIndexExpr &) +{} + +void +ResolverBase::visit (AST::TupleExpr &) +{} + +void +ResolverBase::visit (AST::TupleIndexExpr &) +{} + +void +ResolverBase::visit (AST::StructExprStruct &) +{} + +void +ResolverBase::visit (AST::StructExprFieldIdentifier &) +{} + +void +ResolverBase::visit (AST::StructExprFieldIdentifierValue &) +{} + +void +ResolverBase::visit (AST::StructExprFieldIndexValue &) +{} + +void +ResolverBase::visit (AST::StructExprStructFields &) +{} + +void +ResolverBase::visit (AST::StructExprStructBase &) +{} + +void +ResolverBase::visit (AST::CallExpr &) +{} + +void +ResolverBase::visit (AST::MethodCallExpr &) +{} + +void +ResolverBase::visit (AST::FieldAccessExpr &) +{} + +void +ResolverBase::visit (AST::ClosureExprInner &) +{} + +void +ResolverBase::visit (AST::BlockExpr &) +{} + +void +ResolverBase::visit (AST::ClosureExprInnerTyped &) +{} + +void +ResolverBase::visit (AST::ContinueExpr &) +{} + +void +ResolverBase::visit (AST::BreakExpr &) +{} + +void +ResolverBase::visit (AST::RangeFromToExpr &) +{} + +void +ResolverBase::visit (AST::RangeFromExpr &) +{} + +void +ResolverBase::visit (AST::RangeToExpr &) +{} + +void +ResolverBase::visit (AST::RangeFullExpr &) +{} + +void +ResolverBase::visit (AST::RangeFromToInclExpr &) +{} + +void +ResolverBase::visit (AST::RangeToInclExpr &) +{} + +void +ResolverBase::visit (AST::ReturnExpr &) +{} + +void +ResolverBase::visit (AST::UnsafeBlockExpr &) +{} + +void +ResolverBase::visit (AST::LoopExpr &) +{} + +void +ResolverBase::visit (AST::WhileLoopExpr &) +{} + +void +ResolverBase::visit (AST::WhileLetLoopExpr &) +{} + +void +ResolverBase::visit (AST::ForLoopExpr &) +{} + +void +ResolverBase::visit (AST::IfExpr &) +{} + +void +ResolverBase::visit (AST::IfExprConseqElse &) +{} + +void +ResolverBase::visit (AST::IfExprConseqIf &) +{} + +void +ResolverBase::visit (AST::IfExprConseqIfLet &) +{} + +void +ResolverBase::visit (AST::IfLetExpr &) +{} + +void +ResolverBase::visit (AST::IfLetExprConseqElse &) +{} + +void +ResolverBase::visit (AST::IfLetExprConseqIf &) +{} + +void +ResolverBase::visit (AST::IfLetExprConseqIfLet &) +{} + +void +ResolverBase::visit (AST::MatchExpr &) +{} + +void +ResolverBase::visit (AST::AwaitExpr &) +{} + +void +ResolverBase::visit (AST::AsyncBlockExpr &) +{} + +void +ResolverBase::visit (AST::TypeParam &) +{} + +void +ResolverBase::visit (AST::LifetimeWhereClauseItem &) +{} + +void +ResolverBase::visit (AST::TypeBoundWhereClauseItem &) +{} + +void +ResolverBase::visit (AST::Method &) +{} + +void +ResolverBase::visit (AST::Module &) +{} + +void +ResolverBase::visit (AST::ExternCrate &) +{} + +void +ResolverBase::visit (AST::UseTreeGlob &) +{} + +void +ResolverBase::visit (AST::UseTreeList &) +{} + +void +ResolverBase::visit (AST::UseTreeRebind &) +{} + +void +ResolverBase::visit (AST::UseDeclaration &) +{} + +void +ResolverBase::visit (AST::Function &) +{} + +void +ResolverBase::visit (AST::TypeAlias &) +{} + +void +ResolverBase::visit (AST::StructStruct &) +{} + +void +ResolverBase::visit (AST::TupleStruct &) +{} + +void +ResolverBase::visit (AST::EnumItem &) +{} + +void +ResolverBase::visit (AST::EnumItemTuple &) +{} + +void +ResolverBase::visit (AST::EnumItemStruct &) +{} + +void +ResolverBase::visit (AST::EnumItemDiscriminant &) +{} + +void +ResolverBase::visit (AST::Enum &) +{} + +void +ResolverBase::visit (AST::Union &) +{} + +void +ResolverBase::visit (AST::ConstantItem &) +{} + +void +ResolverBase::visit (AST::StaticItem &) +{} + +void +ResolverBase::visit (AST::TraitItemFunc &) +{} + +void +ResolverBase::visit (AST::TraitItemMethod &) +{} + +void +ResolverBase::visit (AST::TraitItemConst &) +{} + +void +ResolverBase::visit (AST::TraitItemType &) +{} + +void +ResolverBase::visit (AST::Trait &) +{} + +void +ResolverBase::visit (AST::InherentImpl &) +{} + +void +ResolverBase::visit (AST::TraitImpl &) +{} + +void +ResolverBase::visit (AST::ExternalStaticItem &) +{} + +void +ResolverBase::visit (AST::ExternalFunctionItem &) +{} + +void +ResolverBase::visit (AST::ExternBlock &) +{} + +void +ResolverBase::visit (AST::MacroMatchFragment &) +{} + +void +ResolverBase::visit (AST::MacroMatchRepetition &) +{} + +void +ResolverBase::visit (AST::MacroMatcher &) +{} + +void +ResolverBase::visit (AST::MacroRulesDefinition &) +{} + +void +ResolverBase::visit (AST::MacroInvocation &) +{} + +void +ResolverBase::visit (AST::MetaItemPath &) +{} + +void +ResolverBase::visit (AST::MetaItemSeq &) +{} + +void +ResolverBase::visit (AST::MetaWord &) +{} + +void +ResolverBase::visit (AST::MetaNameValueStr &) +{} + +void +ResolverBase::visit (AST::MetaListPaths &) +{} + +void +ResolverBase::visit (AST::MetaListNameValueStr &) +{} + +void +ResolverBase::visit (AST::LiteralPattern &) +{} + +void +ResolverBase::visit (AST::IdentifierPattern &) +{} + +void +ResolverBase::visit (AST::WildcardPattern &) +{} + +void +ResolverBase::visit (AST::RangePatternBoundLiteral &) +{} + +void +ResolverBase::visit (AST::RangePatternBoundPath &) +{} + +void +ResolverBase::visit (AST::RangePatternBoundQualPath &) +{} + +void +ResolverBase::visit (AST::RangePattern &) +{} + +void +ResolverBase::visit (AST::ReferencePattern &) +{} + +void +ResolverBase::visit (AST::StructPatternFieldTuplePat &) +{} + +void +ResolverBase::visit (AST::StructPatternFieldIdentPat &) +{} + +void +ResolverBase::visit (AST::StructPatternFieldIdent &) +{} + +void +ResolverBase::visit (AST::StructPattern &) +{} + +void +ResolverBase::visit (AST::TupleStructItemsNoRange &) +{} + +void +ResolverBase::visit (AST::TupleStructItemsRange &) +{} + +void +ResolverBase::visit (AST::TupleStructPattern &) +{} + +void +ResolverBase::visit (AST::TuplePatternItemsMultiple &) +{} + +void +ResolverBase::visit (AST::TuplePatternItemsRanged &) +{} + +void +ResolverBase::visit (AST::TuplePattern &) +{} + +void +ResolverBase::visit (AST::GroupedPattern &) +{} + +void +ResolverBase::visit (AST::SlicePattern &) +{} + +void +ResolverBase::visit (AST::EmptyStmt &) +{} + +void +ResolverBase::visit (AST::LetStmt &) +{} + +void +ResolverBase::visit (AST::ExprStmtWithoutBlock &) +{} + +void +ResolverBase::visit (AST::ExprStmtWithBlock &) +{} + +void +ResolverBase::visit (AST::TraitBound &) +{} + +void +ResolverBase::visit (AST::ImplTraitType &) +{} + +void +ResolverBase::visit (AST::TraitObjectType &) +{} + +void +ResolverBase::visit (AST::ParenthesisedType &) +{} + +void +ResolverBase::visit (AST::ImplTraitTypeOneBound &) +{} + +void +ResolverBase::visit (AST::TraitObjectTypeOneBound &) +{} + +void +ResolverBase::visit (AST::TupleType &) +{} + +void +ResolverBase::visit (AST::NeverType &) +{} + +void +ResolverBase::visit (AST::RawPointerType &) +{} + +void +ResolverBase::visit (AST::ReferenceType &) +{} + +void +ResolverBase::visit (AST::ArrayType &) +{} + +void +ResolverBase::visit (AST::SliceType &) +{} + +void +ResolverBase::visit (AST::InferredType &) +{} + +void +ResolverBase::visit (AST::BareFunctionType &) +{} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/resolve/rust-ast-resolve-base.h b/gcc/rust/resolve/rust-ast-resolve-base.h new file mode 100644 index 00000000000..32f30bcea62 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-base.h @@ -0,0 +1,221 @@ +// 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_RESOLVE_BASE_H +#define RUST_AST_RESOLVE_BASE_H + +#include "rust-ast-visitor.h" +#include "rust-name-resolver.h" +#include "rust-diagnostics.h" +#include "rust-location.h" + +namespace Rust { +namespace Resolver { + +class ResolverBase : public AST::ASTVisitor +{ +public: + virtual ~ResolverBase () {} + + void visit (AST::Token &); + void visit (AST::DelimTokenTree &); + void visit (AST::AttrInputMetaItemContainer &); + void visit (AST::IdentifierExpr &); + void visit (AST::Lifetime &); + void visit (AST::LifetimeParam &); + void visit (AST::ConstGenericParam &); + void visit (AST::PathInExpression &); + void visit (AST::TypePathSegment &); + void visit (AST::TypePathSegmentGeneric &); + void visit (AST::TypePathSegmentFunction &); + void visit (AST::TypePath &); + void visit (AST::QualifiedPathInExpression &); + void visit (AST::QualifiedPathInType &); + void visit (AST::LiteralExpr &); + void visit (AST::AttrInputLiteral &); + void visit (AST::MetaItemLitExpr &); + void visit (AST::MetaItemPathLit &); + void visit (AST::BorrowExpr &); + void visit (AST::DereferenceExpr &); + void visit (AST::ErrorPropagationExpr &); + void visit (AST::NegationExpr &); + void visit (AST::ArithmeticOrLogicalExpr &); + void visit (AST::ComparisonExpr &); + void visit (AST::LazyBooleanExpr &); + void visit (AST::TypeCastExpr &); + void visit (AST::AssignmentExpr &); + void visit (AST::CompoundAssignmentExpr &); + void visit (AST::GroupedExpr &); + void visit (AST::ArrayElemsValues &); + void visit (AST::ArrayElemsCopied &); + void visit (AST::ArrayExpr &); + void visit (AST::ArrayIndexExpr &); + void visit (AST::TupleExpr &); + void visit (AST::TupleIndexExpr &); + void visit (AST::StructExprStruct &); + void visit (AST::StructExprFieldIdentifier &); + void visit (AST::StructExprFieldIdentifierValue &); + void visit (AST::StructExprFieldIndexValue &); + void visit (AST::StructExprStructFields &); + void visit (AST::StructExprStructBase &); + void visit (AST::CallExpr &); + void visit (AST::MethodCallExpr &); + void visit (AST::FieldAccessExpr &); + void visit (AST::ClosureExprInner &); + void visit (AST::BlockExpr &); + void visit (AST::ClosureExprInnerTyped &); + void visit (AST::ContinueExpr &); + void visit (AST::BreakExpr &); + void visit (AST::RangeFromToExpr &); + void visit (AST::RangeFromExpr &); + void visit (AST::RangeToExpr &); + void visit (AST::RangeFullExpr &); + void visit (AST::RangeFromToInclExpr &); + void visit (AST::RangeToInclExpr &); + void visit (AST::ReturnExpr &); + void visit (AST::UnsafeBlockExpr &); + void visit (AST::LoopExpr &); + void visit (AST::WhileLoopExpr &); + void visit (AST::WhileLetLoopExpr &); + void visit (AST::ForLoopExpr &); + void visit (AST::IfExpr &); + void visit (AST::IfExprConseqElse &); + void visit (AST::IfExprConseqIf &); + void visit (AST::IfExprConseqIfLet &); + void visit (AST::IfLetExpr &); + void visit (AST::IfLetExprConseqElse &); + void visit (AST::IfLetExprConseqIf &); + void visit (AST::IfLetExprConseqIfLet &); + + void visit (AST::MatchExpr &); + void visit (AST::AwaitExpr &); + void visit (AST::AsyncBlockExpr &); + + void visit (AST::TypeParam &); + + void visit (AST::LifetimeWhereClauseItem &); + void visit (AST::TypeBoundWhereClauseItem &); + void visit (AST::Method &); + void visit (AST::Module &); + void visit (AST::ExternCrate &); + + void visit (AST::UseTreeGlob &); + void visit (AST::UseTreeList &); + void visit (AST::UseTreeRebind &); + void visit (AST::UseDeclaration &); + void visit (AST::Function &); + void visit (AST::TypeAlias &); + void visit (AST::StructStruct &); + void visit (AST::TupleStruct &); + void visit (AST::EnumItem &); + void visit (AST::EnumItemTuple &); + void visit (AST::EnumItemStruct &); + void visit (AST::EnumItemDiscriminant &); + void visit (AST::Enum &); + void visit (AST::Union &); + void visit (AST::ConstantItem &); + void visit (AST::StaticItem &); + void visit (AST::TraitItemFunc &); + void visit (AST::TraitItemMethod &); + void visit (AST::TraitItemConst &); + void visit (AST::TraitItemType &); + void visit (AST::Trait &); + void visit (AST::InherentImpl &); + void visit (AST::TraitImpl &); + + void visit (AST::ExternalStaticItem &); + void visit (AST::ExternalFunctionItem &); + void visit (AST::ExternBlock &); + + void visit (AST::MacroMatchFragment &); + void visit (AST::MacroMatchRepetition &); + void visit (AST::MacroMatcher &); + void visit (AST::MacroRulesDefinition &); + void visit (AST::MacroInvocation &); + void visit (AST::MetaItemPath &); + void visit (AST::MetaItemSeq &); + void visit (AST::MetaWord &); + void visit (AST::MetaNameValueStr &); + void visit (AST::MetaListPaths &); + void visit (AST::MetaListNameValueStr &); + + void visit (AST::LiteralPattern &); + void visit (AST::IdentifierPattern &); + void visit (AST::WildcardPattern &); + + void visit (AST::RangePatternBoundLiteral &); + void visit (AST::RangePatternBoundPath &); + void visit (AST::RangePatternBoundQualPath &); + void visit (AST::RangePattern &); + void visit (AST::ReferencePattern &); + + void visit (AST::StructPatternFieldTuplePat &); + void visit (AST::StructPatternFieldIdentPat &); + void visit (AST::StructPatternFieldIdent &); + void visit (AST::StructPattern &); + + void visit (AST::TupleStructItemsNoRange &); + void visit (AST::TupleStructItemsRange &); + void visit (AST::TupleStructPattern &); + + void visit (AST::TuplePatternItemsMultiple &); + void visit (AST::TuplePatternItemsRanged &); + void visit (AST::TuplePattern &); + void visit (AST::GroupedPattern &); + void visit (AST::SlicePattern &); + + void visit (AST::EmptyStmt &); + void visit (AST::LetStmt &); + void visit (AST::ExprStmtWithoutBlock &); + void visit (AST::ExprStmtWithBlock &); + + void visit (AST::TraitBound &); + void visit (AST::ImplTraitType &); + void visit (AST::TraitObjectType &); + void visit (AST::ParenthesisedType &); + void visit (AST::ImplTraitTypeOneBound &); + void visit (AST::TraitObjectTypeOneBound &); + void visit (AST::TupleType &); + void visit (AST::NeverType &); + void visit (AST::RawPointerType &); + void visit (AST::ReferenceType &); + void visit (AST::ArrayType &); + void visit (AST::SliceType &); + void visit (AST::InferredType &); + void visit (AST::BareFunctionType &); + +protected: + ResolverBase () + : resolver (Resolver::get ()), mappings (Analysis::Mappings::get ()), + resolved_node (UNKNOWN_NODEID) + {} + + /** + * Resolve a visibility's path through the name resolver + */ + bool resolve_visibility (const AST::Visibility &vis); + + Resolver *resolver; + Analysis::Mappings *mappings; + NodeId resolved_node; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_AST_RESOLVE_BASE_H diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc new file mode 100644 index 00000000000..4cc4e26e3e9 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc @@ -0,0 +1,574 @@ +// 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 +// . + +#include "rust-ast-resolve-expr.h" +#include "rust-ast-resolve-stmt.h" +#include "rust-ast-resolve-struct-expr-field.h" +#include "rust-ast-verify-assignee.h" +#include "rust-ast-resolve-type.h" +#include "rust-ast-resolve-pattern.h" +#include "rust-ast-resolve-path.h" + +namespace Rust { +namespace Resolver { + +void +ResolveExpr::go (AST::Expr *expr, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) +{ + ResolveExpr resolver (prefix, canonical_prefix); + expr->accept_vis (resolver); +} + +void +ResolveExpr::visit (AST::TupleIndexExpr &expr) +{ + ResolveExpr::go (expr.get_tuple_expr ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::TupleExpr &expr) +{ + if (expr.is_unit ()) + return; + + for (auto &elem : expr.get_tuple_elems ()) + ResolveExpr::go (elem.get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::PathInExpression &expr) +{ + ResolvePath::go (&expr); +} + +void +ResolveExpr::visit (AST::QualifiedPathInExpression &expr) +{ + ResolvePath::go (&expr); +} + +void +ResolveExpr::visit (AST::ReturnExpr &expr) +{ + if (expr.has_returned_expr ()) + ResolveExpr::go (expr.get_returned_expr ().get (), prefix, + canonical_prefix); +} + +void +ResolveExpr::visit (AST::CallExpr &expr) +{ + ResolveExpr::go (expr.get_function_expr ().get (), prefix, canonical_prefix); + for (auto ¶m : expr.get_params ()) + ResolveExpr::go (param.get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::MethodCallExpr &expr) +{ + ResolveExpr::go (expr.get_receiver_expr ().get (), prefix, canonical_prefix); + + if (expr.get_method_name ().has_generic_args ()) + { + AST::GenericArgs &args = expr.get_method_name ().get_generic_args (); + ResolveGenericArgs::go (args, prefix, canonical_prefix); + } + + auto const &in_params = expr.get_params (); + for (auto ¶m : in_params) + ResolveExpr::go (param.get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::AssignmentExpr &expr) +{ + ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix); + + // need to verify the assignee + VerifyAsignee::go (expr.get_left_expr ().get (), expr.get_node_id ()); +} + +void +ResolveExpr::visit (AST::IdentifierExpr &expr) +{ + if (resolver->get_name_scope ().lookup ( + CanonicalPath::new_seg (expr.get_node_id (), expr.as_string ()), + &resolved_node)) + { + resolver->insert_resolved_name (expr.get_node_id (), resolved_node); + } + else if (resolver->get_type_scope ().lookup ( + CanonicalPath::new_seg (expr.get_node_id (), expr.as_string ()), + &resolved_node)) + { + resolver->insert_resolved_type (expr.get_node_id (), resolved_node); + } + else + { + rust_error_at (expr.get_locus (), "failed to find name: %s", + expr.as_string ().c_str ()); + } +} + +void +ResolveExpr::visit (AST::ArithmeticOrLogicalExpr &expr) +{ + ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::CompoundAssignmentExpr &expr) +{ + ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix); + + // need to verify the assignee + VerifyAsignee::go (expr.get_left_expr ().get (), expr.get_node_id ()); +} + +void +ResolveExpr::visit (AST::ComparisonExpr &expr) +{ + ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::LazyBooleanExpr &expr) +{ + ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::NegationExpr &expr) +{ + ResolveExpr::go (expr.get_negated_expr ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::TypeCastExpr &expr) +{ + ResolveType::go (expr.get_type_to_cast_to ().get ()); + ResolveExpr::go (expr.get_casted_expr ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::IfExpr &expr) +{ + ResolveExpr::go (expr.get_condition_expr ().get (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::IfExprConseqElse &expr) +{ + ResolveExpr::go (expr.get_condition_expr ().get (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_else_block ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::IfExprConseqIf &expr) +{ + ResolveExpr::go (expr.get_condition_expr ().get (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_conseq_if_expr ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::IfLetExpr &expr) +{ + ResolveExpr::go (expr.get_value_expr ().get (), prefix, canonical_prefix); + + NodeId scope_node_id = expr.get_node_id (); + resolver->get_name_scope ().push (scope_node_id); + resolver->get_type_scope ().push (scope_node_id); + resolver->get_label_scope ().push (scope_node_id); + resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); + resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + + for (auto &pattern : expr.get_patterns ()) + { + PatternDeclaration::go (pattern.get ()); + } + + ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix); + + resolver->get_name_scope ().pop (); + resolver->get_type_scope ().pop (); + resolver->get_label_scope ().pop (); +} + +void +ResolveExpr::visit (AST::BlockExpr &expr) +{ + NodeId scope_node_id = expr.get_node_id (); + resolver->get_name_scope ().push (scope_node_id); + resolver->get_type_scope ().push (scope_node_id); + resolver->get_label_scope ().push (scope_node_id); + resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); + resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + + for (auto &s : expr.get_statements ()) + { + if (s->is_item ()) + ResolveStmt::go (s.get (), prefix, canonical_prefix, + CanonicalPath::create_empty ()); + } + + for (auto &s : expr.get_statements ()) + { + if (!s->is_item ()) + ResolveStmt::go (s.get (), prefix, canonical_prefix, + CanonicalPath::create_empty ()); + } + + if (expr.has_tail_expr ()) + ResolveExpr::go (expr.get_tail_expr ().get (), prefix, canonical_prefix); + + resolver->get_name_scope ().pop (); + resolver->get_type_scope ().pop (); + resolver->get_label_scope ().pop (); +} + +void +ResolveExpr::visit (AST::UnsafeBlockExpr &expr) +{ + expr.get_block_expr ()->accept_vis (*this); +} + +void +ResolveExpr::visit (AST::ArrayElemsValues &elems) +{ + for (auto &elem : elems.get_values ()) + ResolveExpr::go (elem.get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::ArrayExpr &expr) +{ + expr.get_array_elems ()->accept_vis (*this); +} + +void +ResolveExpr::visit (AST::ArrayIndexExpr &expr) +{ + ResolveExpr::go (expr.get_array_expr ().get (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_index_expr ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::ArrayElemsCopied &expr) +{ + ResolveExpr::go (expr.get_num_copies ().get (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_elem_to_copy ().get (), prefix, canonical_prefix); +} + +// this this an empty struct constructor like 'S {}' +void +ResolveExpr::visit (AST::StructExprStruct &struct_expr) +{ + ResolveExpr::go (&struct_expr.get_struct_name (), prefix, canonical_prefix); +} + +// this this a struct constructor with fields +void +ResolveExpr::visit (AST::StructExprStructFields &struct_expr) +{ + ResolveExpr::go (&struct_expr.get_struct_name (), prefix, canonical_prefix); + + if (struct_expr.has_struct_base ()) + { + AST::StructBase &base = struct_expr.get_struct_base (); + ResolveExpr::go (base.get_base_struct ().get (), prefix, + canonical_prefix); + } + + auto const &struct_fields = struct_expr.get_fields (); + for (auto &struct_field : struct_fields) + { + ResolveStructExprField::go (struct_field.get (), prefix, + canonical_prefix); + } +} + +void +ResolveExpr::visit (AST::GroupedExpr &expr) +{ + ResolveExpr::go (expr.get_expr_in_parens ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::FieldAccessExpr &expr) +{ + ResolveExpr::go (expr.get_receiver_expr ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::LoopExpr &expr) +{ + if (expr.has_loop_label ()) + { + auto label = expr.get_loop_label (); + if (label.get_lifetime ().get_lifetime_type () + != AST::Lifetime::LifetimeType::NAMED) + { + rust_error_at (label.get_locus (), + "Labels must be a named lifetime value"); + return; + } + + auto label_name = label.get_lifetime ().get_lifetime_name (); + auto label_lifetime_node_id = label.get_lifetime ().get_node_id (); + resolver->get_label_scope ().insert ( + CanonicalPath::new_seg (expr.get_node_id (), label_name), + label_lifetime_node_id, label.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + rust_error_at (label.get_locus (), "label redefined multiple times"); + rust_error_at (locus, "was defined here"); + }); + } + ResolveExpr::go (expr.get_loop_block ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::BreakExpr &expr) +{ + if (expr.has_label ()) + { + auto label = expr.get_label (); + if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED) + { + rust_error_at (label.get_locus (), + "Labels must be a named lifetime value"); + return; + } + + NodeId resolved_node = UNKNOWN_NODEID; + if (!resolver->get_label_scope ().lookup ( + CanonicalPath::new_seg (label.get_node_id (), + label.get_lifetime_name ()), + &resolved_node)) + { + rust_error_at (expr.get_label ().get_locus (), + "failed to resolve label"); + return; + } + resolver->insert_resolved_label (label.get_node_id (), resolved_node); + } + + if (expr.has_break_expr ()) + ResolveExpr::go (expr.get_break_expr ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::WhileLoopExpr &expr) +{ + if (expr.has_loop_label ()) + { + auto label = expr.get_loop_label (); + if (label.get_lifetime ().get_lifetime_type () + != AST::Lifetime::LifetimeType::NAMED) + { + rust_error_at (label.get_locus (), + "Labels must be a named lifetime value"); + return; + } + + auto label_name = label.get_lifetime ().get_lifetime_name (); + auto label_lifetime_node_id = label.get_lifetime ().get_node_id (); + resolver->get_label_scope ().insert ( + CanonicalPath::new_seg (label.get_node_id (), label_name), + label_lifetime_node_id, label.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + rust_error_at (label.get_locus (), "label redefined multiple times"); + rust_error_at (locus, "was defined here"); + }); + } + + ResolveExpr::go (expr.get_predicate_expr ().get (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_loop_block ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::ForLoopExpr &expr) +{ + if (expr.has_loop_label ()) + { + auto label = expr.get_loop_label (); + if (label.get_lifetime ().get_lifetime_type () + != AST::Lifetime::LifetimeType::NAMED) + { + rust_error_at (label.get_locus (), + "Labels must be a named lifetime value"); + return; + } + + auto label_name = label.get_lifetime ().get_lifetime_name (); + auto label_lifetime_node_id = label.get_lifetime ().get_node_id (); + resolver->get_label_scope ().insert ( + CanonicalPath::new_seg (label.get_node_id (), label_name), + label_lifetime_node_id, label.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + rust_error_at (label.get_locus (), "label redefined multiple times"); + rust_error_at (locus, "was defined here"); + }); + } + + // this needs a new rib to contain the pattern + NodeId scope_node_id = expr.get_node_id (); + resolver->get_name_scope ().push (scope_node_id); + resolver->get_type_scope ().push (scope_node_id); + resolver->get_label_scope ().push (scope_node_id); + resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); + resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + + // resolve the expression + PatternDeclaration::go (expr.get_pattern ().get ()); + ResolveExpr::go (expr.get_iterator_expr ().get (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_loop_block ().get (), prefix, canonical_prefix); + + // done + resolver->get_name_scope ().pop (); + resolver->get_type_scope ().pop (); + resolver->get_label_scope ().pop (); +} + +void +ResolveExpr::visit (AST::ContinueExpr &expr) +{ + if (expr.has_label ()) + { + auto label = expr.get_label (); + if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED) + { + rust_error_at (label.get_locus (), + "Labels must be a named lifetime value"); + return; + } + + NodeId resolved_node = UNKNOWN_NODEID; + if (!resolver->get_label_scope ().lookup ( + CanonicalPath::new_seg (label.get_node_id (), + label.get_lifetime_name ()), + &resolved_node)) + { + rust_error_at (expr.get_label ().get_locus (), + "failed to resolve label"); + return; + } + resolver->insert_resolved_label (label.get_node_id (), resolved_node); + } +} + +void +ResolveExpr::visit (AST::BorrowExpr &expr) +{ + ResolveExpr::go (expr.get_borrowed_expr ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::DereferenceExpr &expr) +{ + ResolveExpr::go (expr.get_dereferenced_expr ().get (), prefix, + canonical_prefix); +} + +void +ResolveExpr::visit (AST::MatchExpr &expr) +{ + ResolveExpr::go (expr.get_scrutinee_expr ().get (), prefix, canonical_prefix); + for (auto &match_case : expr.get_match_cases ()) + { + // each arm is in its own scope + NodeId scope_node_id = match_case.get_node_id (); + resolver->get_name_scope ().push (scope_node_id); + resolver->get_type_scope ().push (scope_node_id); + resolver->get_label_scope ().push (scope_node_id); + resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); + resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + + // resolve + AST::MatchArm &arm = match_case.get_arm (); + if (arm.has_match_arm_guard ()) + ResolveExpr::go (arm.get_guard_expr ().get (), prefix, + canonical_prefix); + + // insert any possible new patterns + for (auto &pattern : arm.get_patterns ()) + { + PatternDeclaration::go (pattern.get ()); + } + + // resolve the body + ResolveExpr::go (match_case.get_expr ().get (), prefix, canonical_prefix); + + // done + resolver->get_name_scope ().pop (); + resolver->get_type_scope ().pop (); + resolver->get_label_scope ().pop (); + } +} + +void +ResolveExpr::visit (AST::RangeFromToExpr &expr) +{ + ResolveExpr::go (expr.get_from_expr ().get (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_to_expr ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::RangeFromExpr &expr) +{ + ResolveExpr::go (expr.get_from_expr ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::RangeToExpr &expr) +{ + ResolveExpr::go (expr.get_to_expr ().get (), prefix, canonical_prefix); +} + +void +ResolveExpr::visit (AST::RangeFullExpr &expr) +{ + // nothing to do +} + +void +ResolveExpr::visit (AST::RangeFromToInclExpr &expr) +{ + ResolveExpr::go (expr.get_from_expr ().get (), prefix, canonical_prefix); + ResolveExpr::go (expr.get_to_expr ().get (), prefix, canonical_prefix); +} + +ResolveExpr::ResolveExpr (const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) + : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix) +{} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h new file mode 100644 index 00000000000..11a846ac8cd --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -0,0 +1,133 @@ +// 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_RESOLVE_EXPR_H +#define RUST_AST_RESOLVE_EXPR_H + +#include "rust-ast-resolve-base.h" +#include "rust-ast-full.h" + +namespace Rust { +namespace Resolver { + +class ResolveExpr : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static void go (AST::Expr *expr, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix); + + void visit (AST::TupleIndexExpr &expr) override; + + void visit (AST::TupleExpr &expr) override; + + void visit (AST::PathInExpression &expr) override; + + void visit (AST::QualifiedPathInExpression &expr) override; + + void visit (AST::ReturnExpr &expr) override; + + void visit (AST::CallExpr &expr) override; + + void visit (AST::MethodCallExpr &expr) override; + + void visit (AST::AssignmentExpr &expr) override; + + void visit (AST::IdentifierExpr &expr) override; + + void visit (AST::ArithmeticOrLogicalExpr &expr) override; + + void visit (AST::CompoundAssignmentExpr &expr) override; + + void visit (AST::ComparisonExpr &expr) override; + + void visit (AST::LazyBooleanExpr &expr) override; + + void visit (AST::NegationExpr &expr) override; + + void visit (AST::TypeCastExpr &expr) override; + + void visit (AST::IfExpr &expr) override; + + void visit (AST::IfExprConseqElse &expr) override; + + void visit (AST::IfExprConseqIf &expr) override; + + void visit (AST::IfLetExpr &expr) override; + + void visit (AST::BlockExpr &expr) override; + + void visit (AST::UnsafeBlockExpr &expr) override; + + void visit (AST::ArrayElemsValues &elems) override; + + void visit (AST::ArrayExpr &expr) override; + + void visit (AST::ArrayIndexExpr &expr) override; + + void visit (AST::ArrayElemsCopied &elems) override; + + // this this an empty struct constructor like 'S {}' + void visit (AST::StructExprStruct &struct_expr) override; + + // this this a struct constructor with fields + void visit (AST::StructExprStructFields &struct_expr) override; + + void visit (AST::GroupedExpr &expr) override; + + void visit (AST::FieldAccessExpr &expr) override; + + void visit (AST::LoopExpr &expr) override; + + void visit (AST::BreakExpr &expr) override; + + void visit (AST::WhileLoopExpr &expr) override; + + void visit (AST::ForLoopExpr &expr) override; + + void visit (AST::ContinueExpr &expr) override; + + void visit (AST::BorrowExpr &expr) override; + + void visit (AST::DereferenceExpr &expr) override; + + void visit (AST::MatchExpr &expr) override; + + void visit (AST::RangeFromToExpr &expr) override; + + void visit (AST::RangeFromExpr &expr) override; + + void visit (AST::RangeToExpr &expr) override; + + void visit (AST::RangeFullExpr &expr) override; + + void visit (AST::RangeFromToInclExpr &expr) override; + +private: + ResolveExpr (const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix); + + const CanonicalPath &prefix; + const CanonicalPath &canonical_prefix; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_AST_RESOLVE_EXPR_H diff --git a/gcc/rust/resolve/rust-ast-resolve-implitem.h b/gcc/rust/resolve/rust-ast-resolve-implitem.h new file mode 100644 index 00000000000..29dbe3436f5 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-implitem.h @@ -0,0 +1,275 @@ +// 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_RESOLVE_IMPLITEM_H +#define RUST_AST_RESOLVE_IMPLITEM_H + +#include "rust-ast-resolve-base.h" +#include "rust-ast-resolve-type.h" +#include "rust-ast-full.h" + +namespace Rust { +namespace Resolver { + +class ResolveToplevelImplItem : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static void go (AST::InherentImplItem *item, const CanonicalPath &prefix) + { + if (item->is_marked_for_strip ()) + return; + + ResolveToplevelImplItem resolver (prefix); + item->accept_vis (resolver); + } + + static void go (AST::TraitImplItem *item, const CanonicalPath &prefix) + { + if (item->is_marked_for_strip ()) + return; + + ResolveToplevelImplItem resolver (prefix); + item->accept_vis (resolver); + } + + void visit (AST::TypeAlias &type) override + { + auto decl + = CanonicalPath::new_seg (type.get_node_id (), type.get_new_type_name ()); + auto path = prefix.append (decl); + + resolver->get_type_scope ().insert ( + path, type.get_node_id (), type.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (type.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + } + + void visit (AST::ConstantItem &constant) override + { + auto decl = CanonicalPath::new_seg (constant.get_node_id (), + constant.get_identifier ()); + auto path = prefix.append (decl); + + resolver->get_name_scope ().insert ( + path, constant.get_node_id (), constant.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (constant.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + } + + void visit (AST::Function &function) override + { + auto decl = CanonicalPath::new_seg (function.get_node_id (), + function.get_function_name ()); + auto path = prefix.append (decl); + + resolver->get_name_scope ().insert ( + path, function.get_node_id (), function.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (function.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + } + + void visit (AST::Method &method) override + { + auto decl = CanonicalPath::new_seg (method.get_node_id (), + method.get_method_name ()); + auto path = prefix.append (decl); + + resolver->get_name_scope ().insert ( + path, method.get_node_id (), method.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (method.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + } + +private: + ResolveToplevelImplItem (const CanonicalPath &prefix) + : ResolverBase (), prefix (prefix) + { + rust_assert (!prefix.is_empty ()); + } + + const CanonicalPath &prefix; +}; + +class ResolveTopLevelTraitItems : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static void go (AST::TraitItem *item, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) + { + ResolveTopLevelTraitItems resolver (prefix, canonical_prefix); + item->accept_vis (resolver); + }; + + void visit (AST::TraitItemFunc &function) override + { + auto decl = CanonicalPath::new_seg ( + function.get_node_id (), + function.get_trait_function_decl ().get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + resolver->get_name_scope ().insert ( + path, function.get_node_id (), function.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (function.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + mappings->insert_canonical_path (function.get_node_id (), cpath); + } + + void visit (AST::TraitItemMethod &method) override + { + auto decl = CanonicalPath::new_seg ( + method.get_node_id (), method.get_trait_method_decl ().get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + resolver->get_name_scope ().insert ( + path, method.get_node_id (), method.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (method.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + mappings->insert_canonical_path (method.get_node_id (), cpath); + } + + void visit (AST::TraitItemConst &constant) override + { + auto decl = CanonicalPath::new_seg (constant.get_node_id (), + constant.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + resolver->get_name_scope ().insert ( + path, constant.get_node_id (), constant.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (constant.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + mappings->insert_canonical_path (constant.get_node_id (), cpath); + } + + void visit (AST::TraitItemType &type) override + { + auto decl + = CanonicalPath::new_seg (type.get_node_id (), type.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + resolver->get_type_scope ().insert ( + path, type.get_node_id (), type.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (type.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + mappings->insert_canonical_path (type.get_node_id (), cpath); + } + +private: + ResolveTopLevelTraitItems (const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) + : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix) + {} + + const CanonicalPath &prefix; + const CanonicalPath &canonical_prefix; +}; + +class ResolveToplevelExternItem : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static void go (AST::ExternalItem *item, const CanonicalPath &prefix) + { + ResolveToplevelExternItem resolver (prefix); + item->accept_vis (resolver); + }; + + void visit (AST::ExternalFunctionItem &function) override + { + auto decl = CanonicalPath::new_seg (function.get_node_id (), + function.get_identifier ()); + auto path = prefix.append (decl); + + resolver->get_name_scope ().insert ( + path, function.get_node_id (), function.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (function.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + NodeId current_module = resolver->peek_current_module_scope (); + mappings->insert_module_child_item (current_module, decl); + } + + void visit (AST::ExternalStaticItem &item) override + { + auto decl + = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()); + auto path = prefix.append (decl); + + resolver->get_name_scope ().insert ( + path, item.get_node_id (), item.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (item.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + NodeId current_module = resolver->peek_current_module_scope (); + mappings->insert_module_child_item (current_module, decl); + } + +private: + ResolveToplevelExternItem (const CanonicalPath &prefix) + : ResolverBase (), prefix (prefix) + {} + + const CanonicalPath &prefix; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_AST_RESOLVE_IMPLITEM_H diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc new file mode 100644 index 00000000000..0c38f28d530 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-item.cc @@ -0,0 +1,1237 @@ +// 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 +// . + +#include "rust-ast-resolve-item.h" +#include "rust-ast-resolve-path.h" +#include "selftest.h" + +namespace Rust { +namespace Resolver { + +ResolveTraitItems::ResolveTraitItems (const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) + : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix) +{} + +void +ResolveTraitItems::go (AST::TraitItem *item, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) +{ + if (item->is_marked_for_strip ()) + return; + + ResolveTraitItems resolver (prefix, canonical_prefix); + item->accept_vis (resolver); +} + +void +ResolveTraitItems::visit (AST::TraitItemType &type) +{ + auto decl + = CanonicalPath::new_seg (type.get_node_id (), type.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (type.get_node_id (), cpath); + + for (auto &bound : type.get_type_param_bounds ()) + ResolveTypeBound::go (bound.get ()); +} + +void +ResolveTraitItems::visit (AST::TraitItemFunc &func) +{ + auto decl = CanonicalPath::new_seg ( + func.get_node_id (), func.get_trait_function_decl ().get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (func.get_node_id (), cpath); + + NodeId scope_node_id = func.get_node_id (); + resolver->get_name_scope ().push (scope_node_id); + resolver->get_type_scope ().push (scope_node_id); + resolver->get_label_scope ().push (scope_node_id); + resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); + resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + + AST::TraitFunctionDecl &function = func.get_trait_function_decl (); + if (function.has_generics ()) + for (auto &generic : function.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + + if (function.has_return_type ()) + ResolveType::go (function.get_return_type ().get ()); + + // we make a new scope so the names of parameters are resolved and shadowed + // correctly + for (auto ¶m : function.get_function_params ()) + { + ResolveType::go (param.get_type ().get ()); + PatternDeclaration::go (param.get_pattern ().get ()); + } + + if (function.has_where_clause ()) + ResolveWhereClause::Resolve (function.get_where_clause ()); + + // trait items have an optional body + if (func.has_definition ()) + ResolveExpr::go (func.get_definition ().get (), path, cpath); + + resolver->get_name_scope ().pop (); + resolver->get_type_scope ().pop (); + resolver->get_label_scope ().pop (); +} + +void +ResolveTraitItems::visit (AST::TraitItemMethod &func) +{ + auto decl + = CanonicalPath::new_seg (func.get_node_id (), + func.get_trait_method_decl ().get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (func.get_node_id (), cpath); + + NodeId scope_node_id = func.get_node_id (); + resolver->get_name_scope ().push (scope_node_id); + resolver->get_type_scope ().push (scope_node_id); + resolver->get_label_scope ().push (scope_node_id); + resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); + resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + + AST::TraitMethodDecl &function = func.get_trait_method_decl (); + if (function.has_generics ()) + for (auto &generic : function.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + + if (function.has_return_type ()) + ResolveType::go (function.get_return_type ().get ()); + + // self turns into (self: Self) as a function param + AST::SelfParam &self_param = function.get_self_param (); + AST::IdentifierPattern self_pattern (self_param.get_node_id (), "self", + self_param.get_locus (), + self_param.get_has_ref (), + self_param.get_is_mut (), + std::unique_ptr (nullptr)); + + std::vector> segments; + segments.push_back (std::unique_ptr ( + new AST::TypePathSegment ("Self", false, self_param.get_locus ()))); + + AST::TypePath self_type_path (std::move (segments), self_param.get_locus ()); + + ResolveType::go (&self_type_path); + PatternDeclaration::go (&self_pattern); + + // we make a new scope so the names of parameters are resolved and shadowed + // correctly + for (auto ¶m : function.get_function_params ()) + { + ResolveType::go (param.get_type ().get ()); + PatternDeclaration::go (param.get_pattern ().get ()); + } + + if (function.has_where_clause ()) + ResolveWhereClause::Resolve (function.get_where_clause ()); + + // trait items have an optional body + if (func.has_definition ()) + ResolveExpr::go (func.get_definition ().get (), path, cpath); + + resolver->get_name_scope ().pop (); + resolver->get_type_scope ().pop (); + resolver->get_label_scope ().pop (); +} + +void +ResolveTraitItems::visit (AST::TraitItemConst &constant) +{ + auto decl = CanonicalPath::new_seg (constant.get_node_id (), + constant.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (constant.get_node_id (), cpath); + + ResolveType::go (constant.get_type ().get ()); + + if (constant.has_expr ()) + ResolveExpr::go (constant.get_expr ().get (), path, cpath); +} + +ResolveItem::ResolveItem (const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) + : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix) +{} + +void +ResolveItem::go (AST::Item *item, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) +{ + ResolveItem resolver (prefix, canonical_prefix); + item->accept_vis (resolver); +} + +void +ResolveItem::visit (AST::TypeAlias &alias) +{ + auto talias + = CanonicalPath::new_seg (alias.get_node_id (), alias.get_new_type_name ()); + auto path = prefix.append (talias); + auto cpath = canonical_prefix.append (talias); + mappings->insert_canonical_path (alias.get_node_id (), cpath); + + NodeId scope_node_id = alias.get_node_id (); + resolver->get_type_scope ().push (scope_node_id); + + if (alias.has_generics ()) + for (auto &generic : alias.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + + if (alias.has_where_clause ()) + ResolveWhereClause::Resolve (alias.get_where_clause ()); + + ResolveType::go (alias.get_type_aliased ().get ()); + + resolver->get_type_scope ().pop (); +} + +void +ResolveItem::visit (AST::Module &module) +{ + auto mod = CanonicalPath::new_seg (module.get_node_id (), module.get_name ()); + auto path = prefix.append (mod); + auto cpath = canonical_prefix.append (mod); + mappings->insert_canonical_path (module.get_node_id (), cpath); + + resolve_visibility (module.get_visibility ()); + + NodeId scope_node_id = module.get_node_id (); + resolver->get_name_scope ().push (scope_node_id); + resolver->get_type_scope ().push (scope_node_id); + resolver->get_label_scope ().push (scope_node_id); + resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); + resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + + // FIXME: Should we reinsert a child here? Any reason we ResolveTopLevel::go + // in ResolveTopLevel::visit (AST::Module) as well as here? + for (auto &item : module.get_items ()) + ResolveTopLevel::go (item.get (), CanonicalPath::create_empty (), cpath); + + resolver->push_new_module_scope (module.get_node_id ()); + for (auto &item : module.get_items ()) + ResolveItem::go (item.get (), path, cpath); + + resolver->pop_module_scope (); + + resolver->get_name_scope ().pop (); + resolver->get_type_scope ().pop (); + resolver->get_label_scope ().pop (); +} + +void +ResolveItem::visit (AST::TupleStruct &struct_decl) +{ + auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (), + struct_decl.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (struct_decl.get_node_id (), cpath); + + resolve_visibility (struct_decl.get_visibility ()); + + NodeId scope_node_id = struct_decl.get_node_id (); + resolver->get_type_scope ().push (scope_node_id); + + if (struct_decl.has_generics ()) + for (auto &generic : struct_decl.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + + if (struct_decl.has_where_clause ()) + ResolveWhereClause::Resolve (struct_decl.get_where_clause ()); + + for (AST::TupleField &field : struct_decl.get_fields ()) + { + if (field.get_field_type ()->is_marked_for_strip ()) + continue; + + resolve_visibility (field.get_visibility ()); + + ResolveType::go (field.get_field_type ().get ()); + } + + resolver->get_type_scope ().pop (); +} + +void +ResolveItem::visit (AST::Enum &enum_decl) +{ + auto decl = CanonicalPath::new_seg (enum_decl.get_node_id (), + enum_decl.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (enum_decl.get_node_id (), cpath); + + resolve_visibility (enum_decl.get_visibility ()); + + NodeId scope_node_id = enum_decl.get_node_id (); + resolver->get_type_scope ().push (scope_node_id); + + if (enum_decl.has_generics ()) + for (auto &generic : enum_decl.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, cpath); + + if (enum_decl.has_where_clause ()) + ResolveWhereClause::Resolve (enum_decl.get_where_clause ()); + + /* The actual fields are inside the variants. */ + for (auto &variant : enum_decl.get_variants ()) + ResolveItem::go (variant.get (), path, cpath); + + resolver->get_type_scope ().pop (); +} + +/* EnumItem doesn't need to be handled, no fields. */ +void +ResolveItem::visit (AST::EnumItem &item) +{ + // Since at this point we cannot have visibilities on enum items anymore, we + // can skip handling them + + auto decl + = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (item.get_node_id (), cpath); +} + +void +ResolveItem::visit (AST::EnumItemTuple &item) +{ + auto decl + = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (item.get_node_id (), cpath); + + for (auto &field : item.get_tuple_fields ()) + { + if (field.get_field_type ()->is_marked_for_strip ()) + continue; + + ResolveType::go (field.get_field_type ().get ()); + } +} + +void +ResolveItem::visit (AST::EnumItemStruct &item) +{ + auto decl + = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (item.get_node_id (), cpath); + + for (auto &field : item.get_struct_fields ()) + { + if (field.get_field_type ()->is_marked_for_strip ()) + continue; + + ResolveType::go (field.get_field_type ().get ()); + } +} + +void +ResolveItem::visit (AST::EnumItemDiscriminant &item) +{ + auto decl + = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + mappings->insert_canonical_path (item.get_node_id (), cpath); +} + +void +ResolveItem::visit (AST::StructStruct &struct_decl) +{ + auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (), + struct_decl.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (struct_decl.get_node_id (), cpath); + + resolve_visibility (struct_decl.get_visibility ()); + + NodeId scope_node_id = struct_decl.get_node_id (); + resolver->get_type_scope ().push (scope_node_id); + + if (struct_decl.has_generics ()) + for (auto &generic : struct_decl.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + + if (struct_decl.has_where_clause ()) + ResolveWhereClause::Resolve (struct_decl.get_where_clause ()); + + for (AST::StructField &field : struct_decl.get_fields ()) + { + if (field.get_field_type ()->is_marked_for_strip ()) + continue; + + resolve_visibility (field.get_visibility ()); + + ResolveType::go (field.get_field_type ().get ()); + } + + resolver->get_type_scope ().pop (); +} + +void +ResolveItem::visit (AST::Union &union_decl) +{ + auto decl = CanonicalPath::new_seg (union_decl.get_node_id (), + union_decl.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (union_decl.get_node_id (), cpath); + + resolve_visibility (union_decl.get_visibility ()); + + NodeId scope_node_id = union_decl.get_node_id (); + resolver->get_type_scope ().push (scope_node_id); + + if (union_decl.has_generics ()) + for (auto &generic : union_decl.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + + if (union_decl.has_where_clause ()) + ResolveWhereClause::Resolve (union_decl.get_where_clause ()); + + for (AST::StructField &field : union_decl.get_variants ()) + { + if (field.get_field_type ()->is_marked_for_strip ()) + continue; + + ResolveType::go (field.get_field_type ().get ()); + } + + resolver->get_type_scope ().pop (); +} + +void +ResolveItem::visit (AST::StaticItem &var) +{ + auto decl + = CanonicalPath::new_seg (var.get_node_id (), var.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (var.get_node_id (), cpath); + + ResolveType::go (var.get_type ().get ()); + ResolveExpr::go (var.get_expr ().get (), path, cpath); +} + +void +ResolveItem::visit (AST::ConstantItem &constant) +{ + auto decl = CanonicalPath::new_seg (constant.get_node_id (), + constant.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (constant.get_node_id (), cpath); + + resolve_visibility (constant.get_visibility ()); + + ResolveType::go (constant.get_type ().get ()); + ResolveExpr::go (constant.get_expr ().get (), path, cpath); +} + +void +ResolveItem::visit (AST::Function &function) +{ + auto decl = CanonicalPath::new_seg (function.get_node_id (), + function.get_function_name ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + mappings->insert_canonical_path (function.get_node_id (), cpath); + + resolve_visibility (function.get_visibility ()); + + NodeId scope_node_id = function.get_node_id (); + resolver->get_name_scope ().push (scope_node_id); + resolver->get_type_scope ().push (scope_node_id); + resolver->get_label_scope ().push (scope_node_id); + resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); + resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + + if (function.has_generics ()) + for (auto &generic : function.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + + // resolve any where clause items + if (function.has_where_clause ()) + ResolveWhereClause::Resolve (function.get_where_clause ()); + + if (function.has_return_type ()) + ResolveType::go (function.get_return_type ().get ()); + + // we make a new scope so the names of parameters are resolved and shadowed + // correctly + for (auto ¶m : function.get_function_params ()) + { + ResolveType::go (param.get_type ().get ()); + PatternDeclaration::go (param.get_pattern ().get ()); + + // the mutability checker needs to verify for immutable decls the number + // of assignments are <1. This marks an implicit assignment + } + + // resolve the function body + ResolveExpr::go (function.get_definition ().get (), path, cpath); + + resolver->get_name_scope ().pop (); + resolver->get_type_scope ().pop (); + resolver->get_label_scope ().pop (); +} + +void +ResolveItem::visit (AST::InherentImpl &impl_block) +{ + NodeId scope_node_id = impl_block.get_node_id (); + resolver->get_name_scope ().push (scope_node_id); + resolver->get_type_scope ().push (scope_node_id); + resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); + resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); + + resolve_visibility (impl_block.get_visibility ()); + + if (impl_block.has_generics ()) + for (auto &generic : impl_block.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + + // resolve any where clause items + if (impl_block.has_where_clause ()) + ResolveWhereClause::Resolve (impl_block.get_where_clause ()); + + // FIXME this needs to be protected behind nominal type-checks see: + // rustc --explain E0118 + ResolveType::go (impl_block.get_type ().get ()); + + // Setup paths + CanonicalPath self_cpath = CanonicalPath::create_empty (); + bool ok = ResolveTypeToCanonicalPath::go (impl_block.get_type ().get (), + self_cpath); + rust_assert (ok); + rust_debug ("AST::InherentImpl resolve Self: {%s}", + self_cpath.get ().c_str ()); + + CanonicalPath impl_type = self_cpath; + CanonicalPath impl_prefix = prefix.append (impl_type); + + // see https://godbolt.org/z/a3vMbsT6W + CanonicalPath cpath = CanonicalPath::create_empty (); + if (canonical_prefix.size () <= 1) + { + cpath = self_cpath; + } + else + { + std::string seg_buf = ""; + CanonicalPath seg + = CanonicalPath::new_seg (impl_block.get_node_id (), seg_buf); + cpath = canonical_prefix.append (seg); + } + + // done setup paths + + auto Self + = CanonicalPath::get_big_self (impl_block.get_type ()->get_node_id ()); + + resolver->get_type_scope ().insert (Self, + impl_block.get_type ()->get_node_id (), + impl_block.get_type ()->get_locus ()); + + for (auto &impl_item : impl_block.get_impl_items ()) + { + rust_debug ( + "AST::InherentImpl resolve_impl_item: impl_prefix={%s} cpath={%s}", + impl_prefix.get ().c_str (), cpath.get ().c_str ()); + resolve_impl_item (impl_item.get (), impl_prefix, cpath); + } + + resolver->get_type_scope ().peek ()->clear_name ( + Self, impl_block.get_type ()->get_node_id ()); + + resolver->get_type_scope ().pop (); + resolver->get_name_scope ().pop (); +} + +void +ResolveItem::visit (AST::Method &method) +{ + auto decl + = CanonicalPath::new_seg (method.get_node_id (), method.get_method_name ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (method.get_node_id (), cpath); + + NodeId scope_node_id = method.get_node_id (); + + resolve_visibility (method.get_visibility ()); + + resolver->get_name_scope ().push (scope_node_id); + resolver->get_type_scope ().push (scope_node_id); + resolver->get_label_scope ().push (scope_node_id); + resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); + resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + + if (method.has_generics ()) + for (auto &generic : method.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + + // resolve any where clause items + if (method.has_where_clause ()) + ResolveWhereClause::Resolve (method.get_where_clause ()); + + if (method.has_return_type ()) + ResolveType::go (method.get_return_type ().get ()); + + // self turns into (self: Self) as a function param + AST::SelfParam &self_param = method.get_self_param (); + AST::IdentifierPattern self_pattern (self_param.get_node_id (), "self", + self_param.get_locus (), + self_param.get_has_ref (), + self_param.get_is_mut (), + std::unique_ptr (nullptr)); + + std::vector> segments; + segments.push_back (std::unique_ptr ( + new AST::TypePathSegment ("Self", false, self_param.get_locus ()))); + + AST::TypePath self_type_path (std::move (segments), self_param.get_locus ()); + + ResolveType::go (&self_type_path); + PatternDeclaration::go (&self_pattern); + + // we make a new scope so the names of parameters are resolved and shadowed + // correctly + for (auto ¶m : method.get_function_params ()) + { + ResolveType::go (param.get_type ().get ()); + PatternDeclaration::go (param.get_pattern ().get ()); + } + + // resolve any where clause items + if (method.has_where_clause ()) + ResolveWhereClause::Resolve (method.get_where_clause ()); + + // resolve the function body + ResolveExpr::go (method.get_definition ().get (), path, cpath); + + resolver->get_name_scope ().pop (); + resolver->get_type_scope ().pop (); + resolver->get_label_scope ().pop (); +} + +void +ResolveItem::visit (AST::TraitImpl &impl_block) +{ + NodeId scope_node_id = impl_block.get_node_id (); + + resolve_visibility (impl_block.get_visibility ()); + + resolver->get_name_scope ().push (scope_node_id); + resolver->get_type_scope ().push (scope_node_id); + resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); + resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); + + if (impl_block.has_generics ()) + for (auto &generic : impl_block.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + + // resolve any where clause items + if (impl_block.has_where_clause ()) + ResolveWhereClause::Resolve (impl_block.get_where_clause ()); + + // CanonicalPath canonical_trait_type = CanonicalPath::create_empty (); + NodeId trait_resolved_node = ResolveType::go (&impl_block.get_trait_path ()); + if (trait_resolved_node == UNKNOWN_NODEID) + { + resolver->get_type_scope ().pop (); + resolver->get_name_scope ().pop (); + return; + } + + // CanonicalPath canonical_impl_type = CanonicalPath::create_empty (); + NodeId type_resolved_node = ResolveType::go (impl_block.get_type ().get ()); + if (type_resolved_node == UNKNOWN_NODEID) + { + resolver->get_type_scope ().pop (); + resolver->get_name_scope ().pop (); + return; + } + + bool ok; + // setup paths + CanonicalPath canonical_trait_type = CanonicalPath::create_empty (); + ok = ResolveTypeToCanonicalPath::go (&impl_block.get_trait_path (), + canonical_trait_type); + rust_assert (ok); + + rust_debug ("AST::TraitImpl resolve trait type: {%s}", + canonical_trait_type.get ().c_str ()); + + CanonicalPath canonical_impl_type = CanonicalPath::create_empty (); + ok = ResolveTypeToCanonicalPath::go (impl_block.get_type ().get (), + canonical_impl_type); + rust_assert (ok); + + rust_debug ("AST::TraitImpl resolve self: {%s}", + canonical_impl_type.get ().c_str ()); + + // raw paths + CanonicalPath impl_type_seg = canonical_impl_type; + CanonicalPath trait_type_seg = canonical_trait_type; + CanonicalPath projection + = CanonicalPath::trait_impl_projection_seg (impl_block.get_node_id (), + trait_type_seg, impl_type_seg); + CanonicalPath impl_prefix = prefix.append (projection); + + // setup canonical-path + CanonicalPath canonical_projection + = CanonicalPath::trait_impl_projection_seg (impl_block.get_node_id (), + canonical_trait_type, + canonical_impl_type); + CanonicalPath cpath = CanonicalPath::create_empty (); + if (canonical_prefix.size () <= 1) + { + cpath = canonical_projection; + } + else + { + std::string projection_str = canonical_projection.get (); + std::string seg_buf + = ""; + CanonicalPath seg + = CanonicalPath::new_seg (impl_block.get_node_id (), seg_buf); + cpath = canonical_prefix.append (seg); + } + + // DONE setup canonical-path + + auto Self + = CanonicalPath::get_big_self (impl_block.get_type ()->get_node_id ()); + + resolver->get_type_scope ().insert (Self, + impl_block.get_type ()->get_node_id (), + impl_block.get_type ()->get_locus ()); + + for (auto &impl_item : impl_block.get_impl_items ()) + { + rust_debug ( + "AST::TraitImpl resolve_impl_item: impl_prefix={%s} cpath={%s}", + impl_prefix.get ().c_str (), cpath.get ().c_str ()); + resolve_impl_item (impl_item.get (), impl_prefix, cpath); + } + + resolver->get_type_scope ().peek ()->clear_name ( + Self, impl_block.get_type ()->get_node_id ()); + resolver->get_type_scope ().pop (); +} + +void +ResolveItem::visit (AST::Trait &trait) +{ + NodeId scope_node_id = trait.get_node_id (); + + resolve_visibility (trait.get_visibility ()); + + resolver->get_name_scope ().push (scope_node_id); + resolver->get_type_scope ().push (scope_node_id); + resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); + resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); + + // we need to inject an implicit self TypeParam here + AST::TypeParam *implicit_self + = new AST::TypeParam ("Self", trait.get_locus ()); + trait.insert_implict_self ( + std::unique_ptr (implicit_self)); + CanonicalPath Self = CanonicalPath::get_big_self (trait.get_node_id ()); + + for (auto &generic : trait.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + + // Self is an implicit TypeParam so lets mark it as such + resolver->get_type_scope ().append_reference_for_def ( + Self.get_node_id (), implicit_self->get_node_id ()); + + if (trait.has_type_param_bounds ()) + { + for (auto &bound : trait.get_type_param_bounds ()) + { + ResolveTypeBound::go (bound.get ()); + } + } + + // resolve any where clause items + if (trait.has_where_clause ()) + ResolveWhereClause::Resolve (trait.get_where_clause ()); + + // resolve the paths + CanonicalPath path = CanonicalPath::create_empty (); + CanonicalPath cpath = CanonicalPath::create_empty (); + // + + for (auto &item : trait.get_trait_items ()) + { + ResolveTraitItems::go (item.get (), path, cpath); + } + + resolver->get_type_scope ().pop (); + resolver->get_name_scope ().pop (); +} + +void +ResolveItem::visit (AST::ExternBlock &extern_block) +{ + resolve_visibility (extern_block.get_visibility ()); + + for (auto &item : extern_block.get_extern_items ()) + { + resolve_extern_item (item.get ()); + } +} + +void +ResolveItem::resolve_impl_item (AST::TraitImplItem *item, + const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) +{ + ResolveImplItems::go (item, prefix, canonical_prefix); +} + +void +ResolveItem::resolve_impl_item (AST::InherentImplItem *item, + const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) +{ + ResolveImplItems::go (item, prefix, canonical_prefix); +} + +void +ResolveItem::resolve_extern_item (AST::ExternalItem *item) +{ + ResolveExternItem::go (item, prefix, canonical_prefix); +} + +static void +flatten_glob (const AST::UseTreeGlob &glob, + std::vector &paths); +static void +flatten_rebind (const AST::UseTreeRebind &glob, + std::vector &paths); +static void +flatten_list (const AST::UseTreeList &glob, + std::vector &paths); + +static void +flatten (const AST::UseTree *tree, std::vector &paths) +{ + switch (tree->get_kind ()) + { + case AST::UseTree::Glob: { + auto glob = static_cast (tree); + flatten_glob (*glob, paths); + break; + } + case AST::UseTree::Rebind: { + auto rebind = static_cast (tree); + flatten_rebind (*rebind, paths); + break; + } + case AST::UseTree::List: { + auto list = static_cast (tree); + flatten_list (*list, paths); + break; + } + break; + } +} + +static void +flatten_glob (const AST::UseTreeGlob &glob, std::vector &paths) +{ + if (glob.has_path ()) + paths.emplace_back (glob.get_path ()); +} + +static void +flatten_rebind (const AST::UseTreeRebind &rebind, + std::vector &paths) +{ + auto path = rebind.get_path (); + if (rebind.has_path ()) + paths.emplace_back (path); + + // FIXME: Do we want to emplace the rebind here as well? + if (rebind.has_identifier ()) + { + auto rebind_path = path; + auto new_seg = rebind.get_identifier (); + + // Add the identifier as a new path + rebind_path.get_segments ().back () + = AST::SimplePathSegment (new_seg, Location ()); + + paths.emplace_back (rebind_path); + } +} + +static void +flatten_list (const AST::UseTreeList &list, std::vector &paths) +{ + auto prefix = AST::SimplePath::create_empty (); + if (list.has_path ()) + prefix = list.get_path (); + + for (const auto &tree : list.get_trees ()) + { + auto sub_paths = std::vector (); + flatten (tree.get (), sub_paths); + + for (auto &sub_path : sub_paths) + { + auto new_path = prefix; + std::copy (sub_path.get_segments ().begin (), + sub_path.get_segments ().end (), + std::back_inserter (new_path.get_segments ())); + + paths.emplace_back (new_path); + } + } +} + +/** + * Flatten a UseDeclaration's UseTree into multiple simple paths to resolve. + * + * Given the following use declarations: + * ``` + * use some::path::to_resolve; #1 + * use some::path::to_glob::*; #2 + * use some::path::{one, two}; #2 + * ``` + * + * In the first case, we simply want to return a vector with a single + * SimplePath: + * [some::path::to_resolve] + * + * In the second case, we want to resolve the glob's "origin path": + * [some::path::to_glob] + * + * Finally in the third case, we want to create two SimplePaths to resolve: + * [some::path::one, some::path::two] + */ +static std::vector +flatten_use_dec_to_paths (const AST::UseDeclaration &use_item) +{ + auto paths = std::vector (); + + const auto &tree = use_item.get_tree (); + flatten (tree.get (), paths); + + return paths; +} + +void +ResolveItem::visit (AST::UseDeclaration &use_item) +{ + auto to_resolve = flatten_use_dec_to_paths (use_item); + + for (auto &path : to_resolve) + ResolvePath::go (&path); +} + +ResolveImplItems::ResolveImplItems (const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) + : ResolveItem (prefix, canonical_prefix) +{} + +void +ResolveImplItems::go (AST::InherentImplItem *item, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) +{ + if (item->is_marked_for_strip ()) + return; + + ResolveImplItems resolver (prefix, canonical_prefix); + item->accept_vis (resolver); +} + +void +ResolveImplItems::go (AST::TraitImplItem *item, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) +{ + if (item->is_marked_for_strip ()) + return; + + ResolveImplItems resolver (prefix, canonical_prefix); + item->accept_vis (resolver); +} + +void +ResolveImplItems::visit (AST::TypeAlias &alias) +{ + ResolveItem::visit (alias); + + resolve_visibility (alias.get_visibility ()); + + // FIXME this stops the erronious unused decls which will be fixed later on + resolver->get_type_scope ().append_reference_for_def (alias.get_node_id (), + alias.get_node_id ()); +} + +void +ResolveExternItem::go (AST::ExternalItem *item, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) +{ + ResolveExternItem resolver (prefix, canonical_prefix); + item->accept_vis (resolver); +} + +void +ResolveExternItem::visit (AST::ExternalFunctionItem &function) +{ + NodeId scope_node_id = function.get_node_id (); + auto decl = CanonicalPath::new_seg (function.get_node_id (), + function.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + mappings->insert_canonical_path (function.get_node_id (), cpath); + + resolve_visibility (function.get_visibility ()); + + resolver->get_name_scope ().push (scope_node_id); + resolver->get_type_scope ().push (scope_node_id); + resolver->get_label_scope ().push (scope_node_id); + resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); + resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + + // resolve the generics + if (function.has_generics ()) + for (auto &generic : function.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + + if (function.has_return_type ()) + ResolveType::go (function.get_return_type ().get ()); + + // we make a new scope so the names of parameters are resolved and shadowed + // correctly + for (auto ¶m : function.get_function_params ()) + { + ResolveType::go (param.get_type ().get ()); + } + + // done + resolver->get_name_scope ().pop (); + resolver->get_type_scope ().pop (); + resolver->get_label_scope ().pop (); +} + +void +ResolveExternItem::visit (AST::ExternalStaticItem &item) +{ + resolve_visibility (item.get_visibility ()); + + ResolveType::go (item.get_type ().get ()); +} + +} // namespace Resolver +} // namespace Rust + +#if CHECKING_P + +namespace selftest { + +static void +rust_flatten_nested_glob (void) +{ + auto foo = Rust::AST::SimplePathSegment ("foo", Location ()); + auto bar = Rust::AST::SimplePathSegment ("bar", Location ()); + auto foobar = Rust::AST::SimplePath ({foo, bar}); + + auto glob + = Rust::AST::UseTreeGlob (Rust::AST::UseTreeGlob::PathType::PATH_PREFIXED, + foobar, Location ()); + + auto paths = std::vector (); + Rust::Resolver::flatten_glob (glob, paths); + + ASSERT_TRUE (!paths.empty ()); + ASSERT_EQ (paths.size (), 1); + ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo"); + ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar"); +} + +static void +rust_flatten_glob (void) +{ + auto frob = Rust::AST::SimplePath::from_str ("frobulator", Location ()); + + auto glob + = Rust::AST::UseTreeGlob (Rust::AST::UseTreeGlob::PathType::PATH_PREFIXED, + frob, Location ()); + + auto paths = std::vector (); + Rust::Resolver::flatten_glob (glob, paths); + + ASSERT_TRUE (!paths.empty ()); + ASSERT_EQ (paths.size (), 1); + ASSERT_EQ (paths[0], "frobulator"); +} + +static void +rust_flatten_rebind_none (void) +{ + auto foo = Rust::AST::SimplePathSegment ("foo", Location ()); + auto bar = Rust::AST::SimplePathSegment ("bar", Location ()); + auto foobar = Rust::AST::SimplePath ({foo, bar}); + + auto rebind = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::NONE, + foobar, Location ()); + + auto paths = std::vector (); + Rust::Resolver::flatten_rebind (rebind, paths); + + ASSERT_TRUE (!paths.empty ()); + ASSERT_EQ (paths.size (), 1); + ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo"); + ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar"); +} + +static void +rust_flatten_rebind (void) +{ + auto frob = Rust::AST::SimplePath::from_str ("frobulator", Location ()); + + auto rebind = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::IDENTIFIER, + frob, Location (), "saindoux"); + + auto paths = std::vector (); + Rust::Resolver::flatten_rebind (rebind, paths); + + ASSERT_TRUE (!paths.empty ()); + ASSERT_EQ (paths.size (), 2); + ASSERT_EQ (paths[0], "frobulator"); + ASSERT_EQ (paths[1], "saindoux"); +} + +static void +rust_flatten_rebind_nested (void) +{ + auto foo = Rust::AST::SimplePathSegment ("foo", Location ()); + auto bar = Rust::AST::SimplePathSegment ("bar", Location ()); + auto baz = Rust::AST::SimplePathSegment ("baz", Location ()); + + auto foo_bar_baz = Rust::AST::SimplePath ({foo, bar, baz}); + + auto rebind = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::IDENTIFIER, + foo_bar_baz, Location (), "saindoux"); + + auto paths = std::vector (); + Rust::Resolver::flatten_rebind (rebind, paths); + + ASSERT_TRUE (!paths.empty ()); + ASSERT_EQ (paths.size (), 2); + ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo"); + ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar"); + ASSERT_EQ (paths[0].get_segments ()[2].as_string (), "baz"); + ASSERT_EQ (paths[1].get_segments ()[0].as_string (), "foo"); + ASSERT_EQ (paths[1].get_segments ()[1].as_string (), "bar"); + ASSERT_EQ (paths[1].get_segments ()[2].as_string (), "saindoux"); +} + +static void +rust_flatten_list (void) +{ + auto foo = Rust::AST::SimplePathSegment ("foo", Location ()); + auto bar = Rust::AST::SimplePathSegment ("bar", Location ()); + auto foo_bar = Rust::AST::SimplePath ({foo, bar}); + + auto baz = Rust::AST::SimplePath::from_str ("baz", Location ()); + auto bul = Rust::AST::SimplePath::from_str ("bul", Location ()); + + // use foo::bar::{baz, bul}; + + auto use0 = std::unique_ptr ( + new Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::NONE, baz, + Location ())); + auto use1 = std::unique_ptr ( + new Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::NONE, bul, + Location ())); + + auto uses = std::vector> (); + uses.emplace_back (std::move (use0)); + uses.emplace_back (std::move (use1)); + + auto list = Rust::AST::UseTreeList (Rust::AST::UseTreeList::PATH_PREFIXED, + foo_bar, std::move (uses), Location ()); + + auto paths = std::vector (); + Rust::Resolver::flatten_list (list, paths); + + for (auto &path : paths) + fprintf (stderr, "%s\n", path.as_string ().c_str ()); + + ASSERT_TRUE (!paths.empty ()); + ASSERT_EQ (paths.size (), 2); + ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo"); + ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar"); + ASSERT_EQ (paths[0].get_segments ()[2].as_string (), "baz"); + ASSERT_EQ (paths[1].get_segments ()[0].as_string (), "foo"); + ASSERT_EQ (paths[1].get_segments ()[1].as_string (), "bar"); + ASSERT_EQ (paths[1].get_segments ()[2].as_string (), "bul"); +} + +static void +rust_use_dec_flattening (void) +{ + rust_flatten_glob (); + rust_flatten_nested_glob (); + rust_flatten_rebind_none (); + rust_flatten_rebind (); + rust_flatten_rebind_nested (); + rust_flatten_list (); +} + +void +rust_simple_path_resolve_test (void) +{ + rust_use_dec_flattening (); +} + +} // namespace selftest + +#endif // CHECKING_P diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h new file mode 100644 index 00000000000..ce521f057f6 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-item.h @@ -0,0 +1,149 @@ +// 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_RESOLVE_ITEM_H +#define RUST_AST_RESOLVE_ITEM_H + +#include "rust-ast-full-decls.h" +#include "rust-ast-resolve-base.h" +#include "rust-ast-full.h" +#include "rust-ast-resolve-toplevel.h" +#include "rust-ast-resolve-type.h" +#include "rust-ast-resolve-pattern.h" +#include "rust-ast-resolve-stmt.h" +#include "config.h" + +namespace Rust { +namespace Resolver { + +class ResolveTraitItems : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static void go (AST::TraitItem *item, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix); + + void visit (AST::TraitItemType &type) override; + void visit (AST::TraitItemFunc &func) override; + void visit (AST::TraitItemMethod &func) override; + void visit (AST::TraitItemConst &constant) override; + +private: + ResolveTraitItems (const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix); + + const CanonicalPath &prefix; + const CanonicalPath &canonical_prefix; +}; + +class ResolveItem : public ResolverBase +{ +public: + using Rust::Resolver::ResolverBase::visit; + + static void go (AST::Item *item, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix); + + void visit (AST::TypeAlias &alias) override; + void visit (AST::Module &module) override; + void visit (AST::TupleStruct &struct_decl) override; + void visit (AST::Enum &enum_decl) override; + /* EnumItem doesn't need to be handled, no fields. */ + void visit (AST::EnumItem &item) override; + void visit (AST::EnumItemTuple &item) override; + void visit (AST::EnumItemStruct &item) override; + void visit (AST::EnumItemDiscriminant &item) override; + void visit (AST::StructStruct &struct_decl) override; + void visit (AST::Union &union_decl) override; + void visit (AST::StaticItem &var) override; + void visit (AST::ConstantItem &constant) override; + void visit (AST::Function &function) override; + void visit (AST::InherentImpl &impl_block) override; + void visit (AST::Method &method) override; + void visit (AST::TraitImpl &impl_block) override; + void visit (AST::Trait &trait) override; + void visit (AST::ExternBlock &extern_block) override; + void visit (AST::UseDeclaration &) override; + +protected: + void resolve_impl_item (AST::TraitImplItem *item, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix); + void resolve_impl_item (AST::InherentImplItem *item, + const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix); + void resolve_extern_item (AST::ExternalItem *item); + + ResolveItem (const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix); + + const CanonicalPath &prefix; + const CanonicalPath &canonical_prefix; +}; + +class ResolveImplItems : public ResolveItem +{ + using Rust::Resolver::ResolveItem::visit; + +public: + static void go (AST::InherentImplItem *item, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix); + static void go (AST::TraitImplItem *item, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix); + + void visit (AST::TypeAlias &alias) override; + +private: + ResolveImplItems (const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix); +}; + +class ResolveExternItem : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static void go (AST::ExternalItem *item, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix); + + void visit (AST::ExternalFunctionItem &function) override; + void visit (AST::ExternalStaticItem &item) override; + +private: + ResolveExternItem (const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) + : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix) + {} + + const CanonicalPath &prefix; + const CanonicalPath &canonical_prefix; +}; + +} // namespace Resolver +} // namespace Rust + +#if CHECKING_P + +namespace selftest { +extern void +rust_simple_path_resolve_test (void); +} // namespace selftest + +#endif // CHECKING_P + +#endif // RUST_AST_RESOLVE_ITEM_H diff --git a/gcc/rust/resolve/rust-ast-resolve-path.cc b/gcc/rust/resolve/rust-ast-resolve-path.cc new file mode 100644 index 00000000000..b139c6a8720 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-path.cc @@ -0,0 +1,384 @@ +// 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 +// . + +#include "rust-ast-resolve-path.h" +#include "rust-ast-resolve-type.h" +#include "rust-path.h" + +namespace Rust { +namespace Resolver { + +ResolvePath::ResolvePath () : ResolverBase () {} + +void +ResolvePath::go (AST::PathInExpression *expr) +{ + ResolvePath resolver; + resolver.resolve_path (expr); +} + +void +ResolvePath::go (AST::QualifiedPathInExpression *expr) +{ + ResolvePath resolver; + resolver.resolve_path (expr); +} + +void +ResolvePath::go (AST::SimplePath *expr) +{ + ResolvePath resolver; + resolver.resolve_path (expr); +} + +void +ResolvePath::resolve_path (AST::PathInExpression *expr) +{ + NodeId resolved_node_id = UNKNOWN_NODEID; + NodeId module_scope_id = resolver->peek_current_module_scope (); + NodeId previous_resolved_node_id = module_scope_id; + for (size_t i = 0; i < expr->get_segments ().size (); i++) + { + auto &segment = expr->get_segments ().at (i); + const AST::PathIdentSegment &ident_seg = segment.get_ident_segment (); + bool is_first_segment = i == 0; + resolved_node_id = UNKNOWN_NODEID; + + bool in_middle_of_path = i > 0; + if (in_middle_of_path && segment.is_lower_self_seg ()) + { + // error[E0433]: failed to resolve: `self` in paths can only be used + // in start position + rust_error_at (segment.get_locus (), + "failed to resolve: %<%s%> in paths can only be used " + "in start position", + segment.as_string ().c_str ()); + return; + } + + NodeId crate_scope_id = resolver->peek_crate_module_scope (); + if (segment.is_crate_path_seg ()) + { + // what is the current crate scope node id? + module_scope_id = crate_scope_id; + previous_resolved_node_id = module_scope_id; + resolver->insert_resolved_name (segment.get_node_id (), + module_scope_id); + continue; + } + else if (segment.is_super_path_seg ()) + { + if (module_scope_id == crate_scope_id) + { + rust_error_at (segment.get_locus (), + "cannot use % at the crate scope"); + return; + } + + module_scope_id = resolver->peek_parent_module_scope (); + previous_resolved_node_id = module_scope_id; + resolver->insert_resolved_name (segment.get_node_id (), + module_scope_id); + continue; + } + + // resolve any generic args + if (segment.has_generic_args ()) + ResolveGenericArgs::go (segment.get_generic_args ()); + + // logic is awkward here there are a few cases + // + // T::Default + // mod::foo::impl_item + // super::super::module::item + // self + // self::foo + // self::foo::baz + // + // T::Default we can only resolve the T and cant do anything about Default + // its dependant on associated types + // + // mod::foo::impl_item + // we can resolve mod::foo but nothing about impl_item but we need to + // _always resolve generic arguments + // + // self is a simple single lookup + // + // we have module_scope_id for the next module_scope to lookup + // resolved_node_id is the thing we have resolve this segment to + // + // new algo? + // we can only use module resolution when the previous segment is either + // unknown or equal to this module_scope_id + // + // can only use old resolution when previous segment is unkown + + if (is_first_segment) + { + // name scope first + NodeId resolved_node = UNKNOWN_NODEID; + const CanonicalPath path + = CanonicalPath::new_seg (segment.get_node_id (), + ident_seg.as_string ()); + if (resolver->get_name_scope ().lookup (path, &resolved_node)) + { + resolver->insert_resolved_name (segment.get_node_id (), + resolved_node); + resolved_node_id = resolved_node; + } + // check the type scope + else if (resolver->get_type_scope ().lookup (path, &resolved_node)) + { + resolver->insert_resolved_type (segment.get_node_id (), + resolved_node); + resolved_node_id = resolved_node; + } + else if (segment.is_lower_self_seg ()) + { + module_scope_id = crate_scope_id; + previous_resolved_node_id = module_scope_id; + resolver->insert_resolved_name (segment.get_node_id (), + module_scope_id); + continue; + } + else + { + // no error handling here since we might be able to resolve via + // the module hierarchy and handle errors at the end + } + } + + if (resolved_node_id == UNKNOWN_NODEID + && previous_resolved_node_id == module_scope_id) + { + Optional resolved_child + = mappings->lookup_module_child (module_scope_id, + ident_seg.as_string ()); + if (resolved_child.is_some ()) + { + NodeId resolved_node = resolved_child->get_node_id (); + if (resolver->get_name_scope ().decl_was_declared_here ( + resolved_node)) + { + resolved_node_id = resolved_node; + resolver->insert_resolved_name (segment.get_node_id (), + resolved_node); + } + else if (resolver->get_type_scope ().decl_was_declared_here ( + resolved_node)) + { + resolved_node_id = resolved_node; + resolver->insert_resolved_type (segment.get_node_id (), + resolved_node); + } + else + { + rust_error_at (segment.get_locus (), + "Cannot find path %<%s%> in this scope", + segment.as_string ().c_str ()); + return; + } + } + } + + bool did_resolve_segment = resolved_node_id != UNKNOWN_NODEID; + if (did_resolve_segment) + { + if (mappings->node_is_module (resolved_node_id) + || mappings->node_is_crate (resolved_node_id)) + { + module_scope_id = resolved_node_id; + } + previous_resolved_node_id = resolved_node_id; + } + else if (is_first_segment) + { + rust_error_at (segment.get_locus (), + "Cannot find path %<%s%> in this scope", + segment.as_string ().c_str ()); + return; + } + } + + resolved_node = resolved_node_id; + if (resolved_node_id != UNKNOWN_NODEID) + { + // name scope first + if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id)) + { + resolver->insert_resolved_name (expr->get_node_id (), + resolved_node_id); + } + // check the type scope + else if (resolver->get_type_scope ().decl_was_declared_here ( + resolved_node_id)) + { + resolver->insert_resolved_type (expr->get_node_id (), + resolved_node_id); + } + else + { + gcc_unreachable (); + } + } +} + +void +ResolvePath::resolve_path (AST::QualifiedPathInExpression *expr) +{ + AST::QualifiedPathType &root_segment = expr->get_qualified_path_type (); + ResolveType::go (root_segment.get_type ().get ()); + if (root_segment.has_as_clause ()) + ResolveType::go (&root_segment.get_as_type_path ()); + + for (auto &segment : expr->get_segments ()) + { + // we cant actually do anything with the segment itself since this is all + // the job of the type system to figure it out but we can resolve any + // generic arguments used + if (segment.has_generic_args ()) + ResolveGenericArgs::go (segment.get_generic_args ()); + } +} + +void +ResolvePath::resolve_path (AST::SimplePath *expr) +{ + NodeId crate_scope_id = resolver->peek_crate_module_scope (); + NodeId module_scope_id = resolver->peek_current_module_scope (); + + NodeId resolved_node_id = UNKNOWN_NODEID; + for (size_t i = 0; i < expr->get_segments ().size (); i++) + { + auto &segment = expr->get_segments ().at (i); + bool is_first_segment = i == 0; + resolved_node_id = UNKNOWN_NODEID; + + if (segment.is_crate_path_seg ()) + { + // what is the current crate scope node id? + module_scope_id = crate_scope_id; + resolver->insert_resolved_name (segment.get_node_id (), + module_scope_id); + continue; + } + else if (segment.is_super_path_seg ()) + { + if (module_scope_id == crate_scope_id) + { + rust_error_at (segment.get_locus (), + "cannot use % at the crate scope"); + return; + } + + module_scope_id = resolver->peek_parent_module_scope (); + resolver->insert_resolved_name (segment.get_node_id (), + module_scope_id); + continue; + } + + Optional resolved_child + = mappings->lookup_module_child (module_scope_id, + segment.get_segment_name ()); + if (resolved_child.is_some ()) + { + NodeId resolved_node = resolved_child->get_node_id (); + if (resolver->get_name_scope ().decl_was_declared_here ( + resolved_node)) + { + resolved_node_id = resolved_node; + resolver->insert_resolved_name (segment.get_node_id (), + resolved_node); + } + else if (resolver->get_type_scope ().decl_was_declared_here ( + resolved_node)) + { + resolved_node_id = resolved_node; + resolver->insert_resolved_type (segment.get_node_id (), + resolved_node); + } + else + { + rust_error_at (segment.get_locus (), + "Cannot find path %<%s%> in this scope", + segment.as_string ().c_str ()); + return; + } + } + + if (resolved_node_id == UNKNOWN_NODEID && is_first_segment) + { + // name scope first + NodeId resolved_node = UNKNOWN_NODEID; + const CanonicalPath path + = CanonicalPath::new_seg (segment.get_node_id (), + segment.get_segment_name ()); + if (resolver->get_name_scope ().lookup (path, &resolved_node)) + { + resolved_node_id = resolved_node; + resolver->insert_resolved_name (segment.get_node_id (), + resolved_node); + } + // check the type scope + else if (resolver->get_type_scope ().lookup (path, &resolved_node)) + { + resolved_node_id = resolved_node; + resolver->insert_resolved_type (segment.get_node_id (), + resolved_node); + } + } + + if (resolved_node_id == UNKNOWN_NODEID) + { + rust_error_at (segment.get_locus (), + "cannot find simple path segment %<%s%> in this scope", + segment.as_string ().c_str ()); + return; + } + + if (mappings->node_is_module (resolved_node_id)) + { + module_scope_id = resolved_node_id; + } + } + + resolved_node = resolved_node_id; + if (resolved_node_id != UNKNOWN_NODEID) + { + // name scope first + if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id)) + { + resolver->insert_resolved_name (expr->get_node_id (), + resolved_node_id); + } + // check the type scope + else if (resolver->get_type_scope ().decl_was_declared_here ( + resolved_node_id)) + { + resolver->insert_resolved_type (expr->get_node_id (), + resolved_node_id); + } + else + { + gcc_unreachable (); + } + } +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/resolve/rust-ast-resolve-path.h b/gcc/rust/resolve/rust-ast-resolve-path.h new file mode 100644 index 00000000000..a9af0c5819c --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-path.h @@ -0,0 +1,52 @@ +// 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_RESOLVE_PATH_H +#define RUST_AST_RESOLVE_PATH_H + +#include "rust-ast-resolve-base.h" + +namespace Rust { +namespace Resolver { + +class ResolvePath : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static void go (AST::PathInExpression *expr); + static void go (AST::QualifiedPathInExpression *expr); + static void go (AST::SimplePath *expr); + +private: + ResolvePath (); + + void resolve_path (AST::PathInExpression *expr); + void resolve_path (AST::QualifiedPathInExpression *expr); + void resolve_path (AST::SimplePath *expr); + + void + resolve_simple_path_segments (CanonicalPath prefix, size_t offs, + const std::vector &segs, + NodeId expr_node_id, Location expr_locus); +}; + +} // namespace Resolver +} // namespace Rust + +#endif // !RUST_AST_RESOLVE_PATH_H diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.cc b/gcc/rust/resolve/rust-ast-resolve-pattern.cc new file mode 100644 index 00000000000..9386d36d25e --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-pattern.cc @@ -0,0 +1,163 @@ +// 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 +// . + +#include "rust-ast-resolve-pattern.h" +#include "rust-ast-resolve-path.h" +#include "rust-ast-resolve-expr.h" + +namespace Rust { +namespace Resolver { + +void +PatternDeclaration::visit (AST::PathInExpression &pattern) +{ + ResolvePath::go (&pattern); +} + +void +PatternDeclaration::visit (AST::TupleStructPattern &pattern) +{ + ResolvePath::go (&pattern.get_path ()); + + std::unique_ptr &items = pattern.get_items (); + switch (items->get_item_type ()) + { + case AST::TupleStructItems::RANGE: { + // TODO + gcc_unreachable (); + } + break; + + case AST::TupleStructItems::NO_RANGE: { + AST::TupleStructItemsNoRange &items_no_range + = static_cast (*items.get ()); + + for (auto &inner_pattern : items_no_range.get_patterns ()) + { + PatternDeclaration::go (inner_pattern.get ()); + } + } + break; + } +} + +void +PatternDeclaration::visit (AST::StructPattern &pattern) +{ + ResolvePath::go (&pattern.get_path ()); + + auto &struct_pattern_elems = pattern.get_struct_pattern_elems (); + for (auto &field : struct_pattern_elems.get_struct_pattern_fields ()) + { + switch (field->get_item_type ()) + { + case AST::StructPatternField::ItemType::TUPLE_PAT: { + // TODO + gcc_unreachable (); + } + break; + + case AST::StructPatternField::ItemType::IDENT_PAT: { + // TODO + gcc_unreachable (); + } + break; + + case AST::StructPatternField::ItemType::IDENT: { + AST::StructPatternFieldIdent &ident + = static_cast (*field.get ()); + + resolver->get_name_scope ().insert ( + CanonicalPath::new_seg (ident.get_node_id (), + ident.get_identifier ()), + ident.get_node_id (), ident.get_locus ()); + } + break; + } + } + + // TODO + rust_assert (!struct_pattern_elems.has_etc ()); +} + +void +PatternDeclaration::visit (AST::TuplePattern &pattern) +{ + std::unique_ptr &items = pattern.get_items (); + switch (items->get_pattern_type ()) + { + case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: { + AST::TuplePatternItemsMultiple &ref + = *static_cast ( + pattern.get_items ().get ()); + + for (auto &p : ref.get_patterns ()) + p->accept_vis (*this); + } + break; + + case AST::TuplePatternItems::TuplePatternItemType::RANGED: { + AST::TuplePatternItemsRanged &ref + = *static_cast ( + pattern.get_items ().get ()); + + for (auto &p : ref.get_lower_patterns ()) + p->accept_vis (*this); + for (auto &p : ref.get_upper_patterns ()) + p->accept_vis (*this); + } + break; + } +} + +static void +resolve_range_pattern_bound (AST::RangePatternBound *bound) +{ + switch (bound->get_bound_type ()) + { + case AST::RangePatternBound::RangePatternBoundType::LITERAL: + // Nothing to resolve for a literal. + break; + + case AST::RangePatternBound::RangePatternBoundType::PATH: { + AST::RangePatternBoundPath &ref + = *static_cast (bound); + + ResolvePath::go (&ref.get_path ()); + } + break; + + case AST::RangePatternBound::RangePatternBoundType::QUALPATH: { + AST::RangePatternBoundQualPath &ref + = *static_cast (bound); + + ResolvePath::go (&ref.get_qualified_path ()); + } + break; + } +} + +void +PatternDeclaration::visit (AST::RangePattern &pattern) +{ + resolve_range_pattern_bound (pattern.get_upper_bound ().get ()); + resolve_range_pattern_bound (pattern.get_lower_bound ().get ()); +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.h b/gcc/rust/resolve/rust-ast-resolve-pattern.h new file mode 100644 index 00000000000..fcbb23fdf08 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-pattern.h @@ -0,0 +1,98 @@ +// 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_RESOLVE_PATTERN_H +#define RUST_AST_RESOLVE_PATTERN_H + +#include "rust-ast-resolve-base.h" +#include "rust-ast-full.h" + +namespace Rust { +namespace Resolver { + +class ResolvePattern : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static void go (AST::Pattern *pattern) + { + ResolvePattern resolver; + pattern->accept_vis (resolver); + } + + void visit (AST::IdentifierPattern &pattern) override + { + if (resolver->get_name_scope ().lookup ( + CanonicalPath::new_seg (pattern.get_node_id (), pattern.get_ident ()), + &resolved_node)) + { + resolver->insert_resolved_name (pattern.get_node_id (), resolved_node); + } + } + +private: + ResolvePattern () : ResolverBase () {} +}; + +class PatternDeclaration : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static void go (AST::Pattern *pattern) + { + PatternDeclaration resolver; + pattern->accept_vis (resolver); + }; + + void visit (AST::IdentifierPattern &pattern) override + { + // if we have a duplicate id this then allows for shadowing correctly + // as new refs to this decl will match back here so it is ok to overwrite + resolver->get_name_scope ().insert ( + CanonicalPath::new_seg (pattern.get_node_id (), pattern.get_ident ()), + pattern.get_node_id (), pattern.get_locus ()); + } + + void visit (AST::WildcardPattern &pattern) override + { + resolver->get_name_scope ().insert ( + CanonicalPath::new_seg (pattern.get_node_id (), "_"), + pattern.get_node_id (), pattern.get_locus ()); + } + + // cases in a match expression + void visit (AST::PathInExpression &pattern) override; + + void visit (AST::StructPattern &pattern) override; + + void visit (AST::TupleStructPattern &pattern) override; + + void visit (AST::TuplePattern &pattern) override; + + void visit (AST::RangePattern &pattern) override; + +private: + PatternDeclaration () : ResolverBase () {} +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_AST_RESOLVE_PATTERN_H diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.cc b/gcc/rust/resolve/rust-ast-resolve-stmt.cc new file mode 100644 index 00000000000..1ce3df0891c --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-stmt.cc @@ -0,0 +1,38 @@ +// 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 +// . + +#include "rust-ast-resolve-item.h" +#include "rust-ast-resolve-stmt.h" + +namespace Rust { +namespace Resolver { + +void +ResolveStmt::visit (AST::ExternBlock &extern_block) +{ + resolve_visibility (extern_block.get_visibility ()); + for (auto &item : extern_block.get_extern_items ()) + { + ResolveToplevelExternItem::go (item.get (), + CanonicalPath::create_empty ()); + ResolveExternItem::go (item.get (), prefix, canonical_prefix); + } +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h new file mode 100644 index 00000000000..6f21bc35a33 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h @@ -0,0 +1,378 @@ +// 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_RESOLVE_STMT_H +#define RUST_AST_RESOLVE_STMT_H + +#include "rust-ast-resolve-base.h" +#include "rust-ast-full.h" +#include "rust-ast-resolve-type.h" +#include "rust-ast-resolve-pattern.h" +#include "rust-ast-resolve-expr.h" + +namespace Rust { +namespace Resolver { + +class ResolveStmt : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static void go (AST::Stmt *stmt, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix, + const CanonicalPath &enum_prefix) + { + if (stmt->is_marked_for_strip ()) + return; + + ResolveStmt resolver (prefix, canonical_prefix, enum_prefix); + stmt->accept_vis (resolver); + } + + void visit (AST::ExprStmtWithBlock &stmt) override + { + ResolveExpr::go (stmt.get_expr ().get (), prefix, canonical_prefix); + } + + void visit (AST::ExprStmtWithoutBlock &stmt) override + { + ResolveExpr::go (stmt.get_expr ().get (), prefix, canonical_prefix); + } + + void visit (AST::ConstantItem &constant) override + { + auto decl = CanonicalPath::new_seg (constant.get_node_id (), + constant.get_identifier ()); + auto path = decl; // this ensures we have the correct relative resolution + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (constant.get_node_id (), cpath); + + resolver->get_name_scope ().insert ( + path, constant.get_node_id (), constant.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (constant.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + ResolveType::go (constant.get_type ().get ()); + ResolveExpr::go (constant.get_expr ().get (), prefix, canonical_prefix); + } + + void visit (AST::LetStmt &stmt) override + { + if (stmt.has_init_expr ()) + { + ResolveExpr::go (stmt.get_init_expr ().get (), prefix, + canonical_prefix); + } + + PatternDeclaration::go (stmt.get_pattern ().get ()); + if (stmt.has_type ()) + ResolveType::go (stmt.get_type ().get ()); + } + + void visit (AST::TupleStruct &struct_decl) override + { + auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (), + struct_decl.get_identifier ()); + auto path = decl; // this ensures we have the correct relative resolution + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (struct_decl.get_node_id (), cpath); + + resolver->get_type_scope ().insert ( + path, struct_decl.get_node_id (), struct_decl.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (struct_decl.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + NodeId scope_node_id = struct_decl.get_node_id (); + resolver->get_type_scope ().push (scope_node_id); + + if (struct_decl.has_generics ()) + { + for (auto &generic : struct_decl.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + } + + for (AST::TupleField &field : struct_decl.get_fields ()) + ResolveType::go (field.get_field_type ().get ()); + + resolver->get_type_scope ().pop (); + } + + void visit (AST::Enum &enum_decl) override + { + auto decl = CanonicalPath::new_seg (enum_decl.get_node_id (), + enum_decl.get_identifier ()); + auto path = decl; // this ensures we have the correct relative resolution + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (enum_decl.get_node_id (), cpath); + + resolver->get_type_scope ().insert ( + path, enum_decl.get_node_id (), enum_decl.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (enum_decl.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + NodeId scope_node_id = enum_decl.get_node_id (); + resolver->get_type_scope ().push (scope_node_id); + + if (enum_decl.has_generics ()) + { + for (auto &generic : enum_decl.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + } + + for (auto &variant : enum_decl.get_variants ()) + ResolveStmt::go (variant.get (), path, canonical_prefix, path); + + resolver->get_type_scope ().pop (); + } + + void visit (AST::EnumItem &item) override + { + auto decl = enum_prefix.append ( + CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ())); + auto path = decl; // this ensures we have the correct relative resolution + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (item.get_node_id (), cpath); + + resolver->get_type_scope ().insert ( + path, item.get_node_id (), item.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (item.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + // Done, no fields. + } + + void visit (AST::EnumItemTuple &item) override + { + auto decl = enum_prefix.append ( + CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ())); + auto path = decl; // this ensures we have the correct relative resolution + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (item.get_node_id (), cpath); + + resolver->get_type_scope ().insert ( + path, item.get_node_id (), item.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (item.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + for (auto &field : item.get_tuple_fields ()) + { + if (field.get_field_type ()->is_marked_for_strip ()) + continue; + + ResolveType::go (field.get_field_type ().get ()); + } + } + + void visit (AST::EnumItemStruct &item) override + { + auto decl = enum_prefix.append ( + CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ())); + auto path = decl; // this ensures we have the correct relative resolution + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (item.get_node_id (), cpath); + + resolver->get_type_scope ().insert ( + path, item.get_node_id (), item.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (item.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + for (auto &field : item.get_struct_fields ()) + { + if (field.get_field_type ()->is_marked_for_strip ()) + continue; + + ResolveType::go (field.get_field_type ().get ()); + } + } + + void visit (AST::EnumItemDiscriminant &item) override + { + auto decl = enum_prefix.append ( + CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ())); + auto path = decl; // this ensures we have the correct relative resolution + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (item.get_node_id (), cpath); + + resolver->get_type_scope ().insert ( + path, item.get_node_id (), item.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (item.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + // Done, no fields. + } + + void visit (AST::StructStruct &struct_decl) override + { + auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (), + struct_decl.get_identifier ()); + auto path = decl; // this ensures we have the correct relative resolution + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (struct_decl.get_node_id (), cpath); + + resolver->get_type_scope ().insert ( + path, struct_decl.get_node_id (), struct_decl.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (struct_decl.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + NodeId scope_node_id = struct_decl.get_node_id (); + resolver->get_type_scope ().push (scope_node_id); + + if (struct_decl.has_generics ()) + { + for (auto &generic : struct_decl.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + } + + for (AST::StructField &field : struct_decl.get_fields ()) + { + if (field.get_field_type ()->is_marked_for_strip ()) + continue; + + ResolveType::go (field.get_field_type ().get ()); + } + + resolver->get_type_scope ().pop (); + } + + void visit (AST::Union &union_decl) override + { + auto decl = CanonicalPath::new_seg (union_decl.get_node_id (), + union_decl.get_identifier ()); + auto path = decl; // this ensures we have the correct relative resolution + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (union_decl.get_node_id (), cpath); + + resolver->get_type_scope ().insert ( + path, union_decl.get_node_id (), union_decl.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (union_decl.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + NodeId scope_node_id = union_decl.get_node_id (); + resolver->get_type_scope ().push (scope_node_id); + + if (union_decl.has_generics ()) + for (auto &generic : union_decl.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + + for (AST::StructField &field : union_decl.get_variants ()) + { + if (field.get_field_type ()->is_marked_for_strip ()) + continue; + + ResolveType::go (field.get_field_type ().get ()); + } + + resolver->get_type_scope ().pop (); + } + + void visit (AST::Function &function) override + { + auto decl = CanonicalPath::new_seg (function.get_node_id (), + function.get_function_name ()); + auto path = decl; // this ensures we have the correct relative resolution + auto cpath = canonical_prefix.append (decl); + mappings->insert_canonical_path (function.get_node_id (), cpath); + + resolver->get_name_scope ().insert ( + path, function.get_node_id (), function.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (function.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + NodeId scope_node_id = function.get_node_id (); + resolver->get_name_scope ().push (scope_node_id); + resolver->get_type_scope ().push (scope_node_id); + resolver->get_label_scope ().push (scope_node_id); + resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); + resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + + if (function.has_generics ()) + for (auto &generic : function.get_generic_params ()) + ResolveGenericParam::go (generic.get (), prefix, canonical_prefix); + + if (function.has_return_type ()) + ResolveType::go (function.get_return_type ().get ()); + + // we make a new scope so the names of parameters are resolved and shadowed + // correctly + for (auto ¶m : function.get_function_params ()) + { + ResolveType::go (param.get_type ().get ()); + PatternDeclaration::go (param.get_pattern ().get ()); + } + + // resolve the function body + ResolveExpr::go (function.get_definition ().get (), path, cpath); + + resolver->get_name_scope ().pop (); + resolver->get_type_scope ().pop (); + resolver->get_label_scope ().pop (); + } + + void visit (AST::ExternBlock &extern_block) override; + +private: + ResolveStmt (const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix, + const CanonicalPath &enum_prefix) + : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix), + enum_prefix (enum_prefix) + {} + + const CanonicalPath &prefix; + const CanonicalPath &canonical_prefix; + + /* item declaration statements are not given a canonical path, but enum items + * (variants) do inherit the enum path/identifier name. */ + const CanonicalPath &enum_prefix; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_AST_RESOLVE_STMT_H diff --git a/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.cc b/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.cc new file mode 100644 index 00000000000..4d8b6c788f3 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.cc @@ -0,0 +1,61 @@ +// 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 +// . + +#include "rust-ast-resolve-struct-expr-field.h" +#include "rust-ast-resolve-expr.h" + +namespace Rust { +namespace Resolver { + +void +ResolveStructExprField::go (AST::StructExprField *field, + const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) +{ + ResolveStructExprField resolver (prefix, canonical_prefix); + field->accept_vis (resolver); +} + +ResolveStructExprField::ResolveStructExprField ( + const CanonicalPath &prefix, const CanonicalPath &canonical_prefix) + : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix) +{} + +void +ResolveStructExprField::visit (AST::StructExprFieldIdentifierValue &field) +{ + ResolveExpr::go (field.get_value ().get (), prefix, canonical_prefix); +} + +void +ResolveStructExprField::visit (AST::StructExprFieldIndexValue &field) +{ + ResolveExpr::go (field.get_value ().get (), prefix, canonical_prefix); +} + +void +ResolveStructExprField::visit (AST::StructExprFieldIdentifier &field) +{ + AST::IdentifierExpr expr (field.get_field_name (), {}, field.get_locus ()); + expr.set_node_id (field.get_node_id ()); + + ResolveExpr::go (&expr, prefix, canonical_prefix); +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.h b/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.h new file mode 100644 index 00000000000..ce60b136e4b --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.h @@ -0,0 +1,55 @@ +// 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_RESOLVE_STRUCT_EXPR_FIELD +#define RUST_AST_RESOLVE_STRUCT_EXPR_FIELD + +#include "rust-ast-resolve-base.h" +#include "rust-ast-full.h" + +namespace Rust { +namespace Resolver { + +// this resolves values being assigned not that the field actually exists yet. + +class ResolveStructExprField : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static void go (AST::StructExprField *field, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix); + + void visit (AST::StructExprFieldIdentifierValue &field) override; + + void visit (AST::StructExprFieldIndexValue &field) override; + + void visit (AST::StructExprFieldIdentifier &field) override; + +private: + ResolveStructExprField (const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix); + + const CanonicalPath &prefix; + const CanonicalPath &canonical_prefix; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_AST_RESOLVE_STRUCT_EXPR_FIELD diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h new file mode 100644 index 00000000000..43ae8e47673 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h @@ -0,0 +1,460 @@ +// 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_RESOLVE_TOPLEVEL_H +#define RUST_AST_RESOLVE_TOPLEVEL_H + +#include "rust-ast-resolve-base.h" +#include "rust-ast-resolve-type.h" +#include "rust-ast-resolve-implitem.h" +#include "rust-ast-full.h" +#include "rust-name-resolver.h" +#include "rust-session-manager.h" + +namespace Rust { +namespace Resolver { + +class ResolveTopLevel : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static void go (AST::Item *item, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) + { + if (item->is_marked_for_strip ()) + return; + + ResolveTopLevel resolver (prefix, canonical_prefix); + item->accept_vis (resolver); + + NodeId current_module = resolver.resolver->peek_current_module_scope (); + resolver.mappings->insert_child_item_to_parent_module_mapping ( + item->get_node_id (), current_module); + } + + void visit (AST::Module &module) override + { + auto mod + = CanonicalPath::new_seg (module.get_node_id (), module.get_name ()); + auto path = prefix.append (mod); + auto cpath = canonical_prefix.append (mod); + + resolver->get_name_scope ().insert ( + path, module.get_node_id (), module.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (module.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + NodeId current_module = resolver->peek_current_module_scope (); + mappings->insert_module_child_item (current_module, mod); + mappings->insert_module_child (current_module, module.get_node_id ()); + + resolver->push_new_module_scope (module.get_node_id ()); + for (auto &item : module.get_items ()) + ResolveTopLevel::go (item.get (), path, cpath); + + resolver->pop_module_scope (); + + mappings->insert_canonical_path (module.get_node_id (), cpath); + } + + void visit (AST::TypeAlias &alias) override + { + auto talias = CanonicalPath::new_seg (alias.get_node_id (), + alias.get_new_type_name ()); + auto path = prefix.append (talias); + auto cpath = canonical_prefix.append (talias); + + resolver->get_type_scope ().insert ( + path, alias.get_node_id (), alias.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (alias.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + NodeId current_module = resolver->peek_current_module_scope (); + mappings->insert_module_child_item (current_module, talias); + mappings->insert_canonical_path (alias.get_node_id (), cpath); + } + + void visit (AST::TupleStruct &struct_decl) override + { + auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (), + struct_decl.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + resolver->get_type_scope ().insert ( + path, struct_decl.get_node_id (), struct_decl.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (struct_decl.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + NodeId current_module = resolver->peek_current_module_scope (); + mappings->insert_module_child_item (current_module, decl); + mappings->insert_canonical_path (struct_decl.get_node_id (), cpath); + } + + void visit (AST::Enum &enum_decl) override + { + auto decl = CanonicalPath::new_seg (enum_decl.get_node_id (), + enum_decl.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + resolver->get_type_scope ().insert ( + path, enum_decl.get_node_id (), enum_decl.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (enum_decl.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + for (auto &variant : enum_decl.get_variants ()) + ResolveTopLevel::go (variant.get (), path, cpath); + + NodeId current_module = resolver->peek_current_module_scope (); + mappings->insert_module_child_item (current_module, decl); + mappings->insert_canonical_path (enum_decl.get_node_id (), cpath); + } + + void visit (AST::EnumItem &item) override + { + auto decl + = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + resolver->get_type_scope ().insert ( + path, item.get_node_id (), item.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (item.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + mappings->insert_canonical_path (item.get_node_id (), cpath); + } + + void visit (AST::EnumItemTuple &item) override + { + auto decl + = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + resolver->get_type_scope ().insert ( + path, item.get_node_id (), item.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (item.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + mappings->insert_canonical_path (item.get_node_id (), cpath); + } + + void visit (AST::EnumItemStruct &item) override + { + auto decl + = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + resolver->get_type_scope ().insert ( + path, item.get_node_id (), item.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (item.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + mappings->insert_canonical_path (item.get_node_id (), cpath); + } + + void visit (AST::EnumItemDiscriminant &item) override + { + auto decl + = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + resolver->get_type_scope ().insert ( + path, item.get_node_id (), item.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (item.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + mappings->insert_canonical_path (item.get_node_id (), cpath); + } + + void visit (AST::StructStruct &struct_decl) override + { + auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (), + struct_decl.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + resolver->get_type_scope ().insert ( + path, struct_decl.get_node_id (), struct_decl.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (struct_decl.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + NodeId current_module = resolver->peek_current_module_scope (); + mappings->insert_module_child_item (current_module, decl); + mappings->insert_canonical_path (struct_decl.get_node_id (), cpath); + } + + void visit (AST::Union &union_decl) override + { + auto decl = CanonicalPath::new_seg (union_decl.get_node_id (), + union_decl.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + resolver->get_type_scope ().insert ( + path, union_decl.get_node_id (), union_decl.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (union_decl.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + NodeId current_module = resolver->peek_current_module_scope (); + mappings->insert_module_child_item (current_module, decl); + mappings->insert_canonical_path (union_decl.get_node_id (), cpath); + } + + void visit (AST::StaticItem &var) override + { + auto decl + = CanonicalPath::new_seg (var.get_node_id (), var.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + resolver->get_name_scope ().insert ( + path, var.get_node_id (), var.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (var.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + NodeId current_module = resolver->peek_current_module_scope (); + mappings->insert_module_child_item (current_module, decl); + mappings->insert_canonical_path (var.get_node_id (), cpath); + } + + void visit (AST::ConstantItem &constant) override + { + auto decl = CanonicalPath::new_seg (constant.get_node_id (), + constant.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + resolver->get_name_scope ().insert ( + path, constant.get_node_id (), constant.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (constant.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + NodeId current_module = resolver->peek_current_module_scope (); + mappings->insert_module_child_item (current_module, decl); + mappings->insert_canonical_path (constant.get_node_id (), cpath); + } + + void visit (AST::Function &function) override + { + auto decl = CanonicalPath::new_seg (function.get_node_id (), + function.get_function_name ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + resolver->get_name_scope ().insert ( + path, function.get_node_id (), function.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (function.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + NodeId current_module = resolver->peek_current_module_scope (); + mappings->insert_module_child_item (current_module, decl); + mappings->insert_canonical_path (function.get_node_id (), cpath); + } + + void visit (AST::InherentImpl &impl_block) override + { + std::string raw_impl_type_path = impl_block.get_type ()->as_string (); + CanonicalPath impl_type + = CanonicalPath::new_seg (impl_block.get_type ()->get_node_id (), + raw_impl_type_path); + CanonicalPath impl_prefix = prefix.append (impl_type); + + for (auto &impl_item : impl_block.get_impl_items ()) + ResolveToplevelImplItem::go (impl_item.get (), impl_prefix); + } + + void visit (AST::TraitImpl &impl_block) override + { + std::string raw_impl_type_path = impl_block.get_type ()->as_string (); + CanonicalPath impl_type_seg + = CanonicalPath::new_seg (impl_block.get_type ()->get_node_id (), + raw_impl_type_path); + + std::string raw_trait_type_path = impl_block.get_trait_path ().as_string (); + CanonicalPath trait_type_seg + = CanonicalPath::new_seg (impl_block.get_trait_path ().get_node_id (), + raw_trait_type_path); + + CanonicalPath projection + = CanonicalPath::trait_impl_projection_seg (impl_block.get_node_id (), + trait_type_seg, + impl_type_seg); + CanonicalPath impl_prefix = prefix.append (projection); + + resolver->get_name_scope ().insert ( + impl_prefix, impl_block.get_node_id (), impl_block.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (impl_block.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + for (auto &impl_item : impl_block.get_impl_items ()) + ResolveToplevelImplItem::go (impl_item.get (), impl_prefix); + } + + void visit (AST::Trait &trait) override + { + auto decl + = CanonicalPath::new_seg (trait.get_node_id (), trait.get_identifier ()); + auto path = prefix.append (decl); + auto cpath = canonical_prefix.append (decl); + + resolver->get_type_scope ().insert ( + path, trait.get_node_id (), trait.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (trait.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + + for (auto &item : trait.get_trait_items ()) + ResolveTopLevelTraitItems::go (item.get (), path, cpath); + + NodeId current_module = resolver->peek_current_module_scope (); + mappings->insert_module_child_item (current_module, decl); + mappings->insert_canonical_path (trait.get_node_id (), cpath); + } + + void visit (AST::ExternBlock &extern_block) override + { + for (auto &item : extern_block.get_extern_items ()) + { + ResolveToplevelExternItem::go (item.get (), prefix); + } + } + + void visit (AST::ExternCrate &extern_crate) override + { + if (extern_crate.is_marked_for_strip ()) + return; + + NodeId resolved_crate = UNKNOWN_NODEID; + if (extern_crate.references_self ()) + { + CrateNum crate_num = mappings->get_current_crate (); + bool ok = mappings->crate_num_to_nodeid (crate_num, resolved_crate); + rust_assert (ok); + } + else + { + CrateNum found_crate_num = UNKNOWN_CREATENUM; + bool found + = mappings->lookup_crate_name (extern_crate.get_referenced_crate (), + found_crate_num); + if (!found) + { + rust_error_at (extern_crate.get_locus (), "unknown crate %<%s%>", + extern_crate.get_referenced_crate ().c_str ()); + return; + } + + bool ok + = mappings->crate_num_to_nodeid (found_crate_num, resolved_crate); + if (!ok) + { + rust_internal_error_at (extern_crate.get_locus (), + "failed to resolve crate to nodeid"); + return; + } + } + + if (resolved_crate == UNKNOWN_NODEID) + { + rust_error_at (extern_crate.get_locus (), "failed to resolve crate"); + return; + } + + // mark the node as resolved + resolver->insert_resolved_name (extern_crate.get_node_id (), + resolved_crate); + CanonicalPath decl + = extern_crate.has_as_clause () + ? CanonicalPath::new_seg (extern_crate.get_node_id (), + extern_crate.get_as_clause ()) + : CanonicalPath::new_seg (extern_crate.get_node_id (), + extern_crate.get_referenced_crate ()); + + resolver->get_type_scope ().insert ( + decl, resolved_crate, extern_crate.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + RichLocation r (extern_crate.get_locus ()); + r.add_range (locus); + rust_error_at (r, "redefined multiple times"); + }); + } + +private: + ResolveTopLevel (const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) + : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix) + {} + + const CanonicalPath &prefix; + const CanonicalPath &canonical_prefix; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_AST_RESOLVE_TOPLEVEL_H diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc new file mode 100644 index 00000000000..6b08613755a --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-type.cc @@ -0,0 +1,582 @@ +// 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 +// . + +#include "rust-ast-resolve-type.h" +#include "rust-ast-resolve-expr.h" + +namespace Rust { +namespace Resolver { + +// rust-ast-resolve-type.h + +void +ResolveType::visit (AST::ArrayType &type) +{ + type.get_elem_type ()->accept_vis (*this); + ResolveExpr::go (type.get_size_expr ().get (), CanonicalPath::create_empty (), + CanonicalPath::create_empty ()); +} + +void +ResolveType::visit (AST::TraitObjectTypeOneBound &type) +{ + ResolveTypeBound::go (&type.get_trait_bound ()); +} + +void +ResolveType::visit (AST::TraitObjectType &type) +{ + for (auto &bound : type.get_type_param_bounds ()) + { + /* NodeId bound_resolved_id = */ + ResolveTypeBound::go (bound.get ()); + } +} + +void +ResolveType::visit (AST::ReferenceType &type) +{ + resolved_node = ResolveType::go (type.get_type_referenced ().get ()); +} + +void +ResolveType::visit (AST::RawPointerType &type) +{ + resolved_node = ResolveType::go (type.get_type_pointed_to ().get ()); +} + +void +ResolveType::visit (AST::InferredType &type) +{ + // FIXME +} + +void +ResolveType::visit (AST::NeverType &type) +{ + // FIXME +} + +void +ResolveType::visit (AST::SliceType &type) +{ + resolved_node = ResolveType::go (type.get_elem_type ().get ()); +} + +// resolve relative type-paths + +bool +ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) +{ + auto resolver = Resolver::get (); + auto mappings = Analysis::Mappings::get (); + + NodeId module_scope_id = resolver->peek_current_module_scope (); + NodeId previous_resolved_node_id = module_scope_id; + for (size_t i = 0; i < path.get_segments ().size (); i++) + { + auto &segment = path.get_segments ().at (i); + const AST::PathIdentSegment &ident_seg = segment->get_ident_segment (); + bool is_first_segment = i == 0; + resolved_node_id = UNKNOWN_NODEID; + + bool in_middle_of_path = i > 0; + if (in_middle_of_path && segment->is_lower_self_seg ()) + { + // error[E0433]: failed to resolve: `self` in paths can only be used + // in start position + rust_error_at (segment->get_locus (), + "failed to resolve: %<%s%> in paths can only be used " + "in start position", + segment->as_string ().c_str ()); + return false; + } + + NodeId crate_scope_id = resolver->peek_crate_module_scope (); + if (segment->is_crate_path_seg ()) + { + // what is the current crate scope node id? + module_scope_id = crate_scope_id; + previous_resolved_node_id = module_scope_id; + resolver->insert_resolved_name (segment->get_node_id (), + module_scope_id); + + continue; + } + else if (segment->is_super_path_seg ()) + { + if (module_scope_id == crate_scope_id) + { + rust_error_at (segment->get_locus (), + "cannot use super at the crate scope"); + return false; + } + + module_scope_id = resolver->peek_parent_module_scope (); + previous_resolved_node_id = module_scope_id; + resolver->insert_resolved_name (segment->get_node_id (), + module_scope_id); + continue; + } + + switch (segment->get_type ()) + { + case AST::TypePathSegment::SegmentType::GENERIC: { + AST::TypePathSegmentGeneric *s + = static_cast (segment.get ()); + if (s->has_generic_args ()) + ResolveGenericArgs::go (s->get_generic_args ()); + } + break; + + case AST::TypePathSegment::SegmentType::REG: + // nothing to do + break; + + case AST::TypePathSegment::SegmentType::FUNCTION: + gcc_unreachable (); + break; + } + + if (is_first_segment) + { + // name scope first + NodeId resolved_node = UNKNOWN_NODEID; + const CanonicalPath path + = CanonicalPath::new_seg (segment->get_node_id (), + ident_seg.as_string ()); + if (resolver->get_type_scope ().lookup (path, &resolved_node)) + { + resolver->insert_resolved_type (segment->get_node_id (), + resolved_node); + resolved_node_id = resolved_node; + } + else if (resolver->get_name_scope ().lookup (path, &resolved_node)) + { + resolver->insert_resolved_name (segment->get_node_id (), + resolved_node); + resolved_node_id = resolved_node; + } + else if (segment->is_lower_self_seg ()) + { + // what is the current crate scope node id? + module_scope_id = crate_scope_id; + previous_resolved_node_id = module_scope_id; + resolver->insert_resolved_name (segment->get_node_id (), + module_scope_id); + + continue; + } + } + + if (resolved_node_id == UNKNOWN_NODEID + && previous_resolved_node_id == module_scope_id) + { + Optional resolved_child + = mappings->lookup_module_child (module_scope_id, + ident_seg.as_string ()); + if (resolved_child.is_some ()) + { + NodeId resolved_node = resolved_child->get_node_id (); + if (resolver->get_name_scope ().decl_was_declared_here ( + resolved_node)) + { + resolved_node_id = resolved_node; + resolver->insert_resolved_name (segment->get_node_id (), + resolved_node); + } + else if (resolver->get_type_scope ().decl_was_declared_here ( + resolved_node)) + { + resolved_node_id = resolved_node; + resolver->insert_resolved_type (segment->get_node_id (), + resolved_node); + } + else + { + rust_error_at (segment->get_locus (), + "Cannot find path %<%s%> in this scope", + segment->as_string ().c_str ()); + return false; + } + } + } + + bool did_resolve_segment = resolved_node_id != UNKNOWN_NODEID; + if (did_resolve_segment) + { + if (mappings->node_is_module (resolved_node_id) + || mappings->node_is_crate (resolved_node_id)) + { + module_scope_id = resolved_node_id; + } + previous_resolved_node_id = resolved_node_id; + } + else if (is_first_segment) + { + rust_error_at (segment->get_locus (), + "failed to resolve TypePath: %s in this scope", + segment->as_string ().c_str ()); + return false; + } + } + + if (resolved_node_id != UNKNOWN_NODEID) + { + // name scope first + if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id)) + { + resolver->insert_resolved_name (path.get_node_id (), + resolved_node_id); + } + // check the type scope + else if (resolver->get_type_scope ().decl_was_declared_here ( + resolved_node_id)) + { + resolver->insert_resolved_type (path.get_node_id (), + resolved_node_id); + } + else + { + gcc_unreachable (); + } + } + + return true; +} + +// qualified type paths + +ResolveRelativeQualTypePath::ResolveRelativeQualTypePath () + : failure_flag (false) +{} + +bool +ResolveRelativeQualTypePath::go (AST::QualifiedPathInType &path) +{ + ResolveRelativeQualTypePath o; + + // resolve the type and trait path + auto &qualified_path = path.get_qualified_path_type (); + if (!o.resolve_qual_seg (qualified_path)) + return false; + + // qualified types are similar to other paths in that we cannot guarantee + // that we can resolve the path at name resolution. We must look up + // associated types and type information to figure this out properly + + std::unique_ptr &associated + = path.get_associated_segment (); + + associated->accept_vis (o); + if (o.failure_flag) + return false; + + for (auto &seg : path.get_segments ()) + { + seg->accept_vis (o); + if (o.failure_flag) + return false; + } + + return true; +} + +bool +ResolveRelativeQualTypePath::resolve_qual_seg (AST::QualifiedPathType &seg) +{ + if (seg.is_error ()) + { + rust_error_at (seg.get_locus (), "segment has error: %s", + seg.as_string ().c_str ()); + return false; + } + + auto type = seg.get_type ().get (); + NodeId type_resolved_node = ResolveType::go (type); + if (type_resolved_node == UNKNOWN_NODEID) + return false; + + if (!seg.has_as_clause ()) + return true; + + NodeId trait_resolved_node = ResolveType::go (&seg.get_as_type_path ()); + if (trait_resolved_node == UNKNOWN_NODEID) + return false; + + return true; +} + +void +ResolveRelativeQualTypePath::visit (AST::TypePathSegmentGeneric &seg) +{ + if (seg.is_error ()) + { + failure_flag = true; + rust_error_at (seg.get_locus (), "segment has error: %s", + seg.as_string ().c_str ()); + return; + } + + ResolveGenericArgs::go (seg.get_generic_args ()); +} + +void +ResolveRelativeQualTypePath::visit (AST::TypePathSegment &seg) +{ + if (seg.is_error ()) + { + failure_flag = true; + rust_error_at (seg.get_locus (), "segment has error: %s", + seg.as_string ().c_str ()); + return; + } +} + +// resolve to canonical path + +bool +ResolveTypeToCanonicalPath::go (AST::Type *type, CanonicalPath &result) +{ + ResolveTypeToCanonicalPath resolver; + type->accept_vis (resolver); + result = resolver.result; + return !resolver.result.is_empty (); +} + +void +ResolveTypeToCanonicalPath::visit (AST::TypePath &path) +{ + NodeId resolved_node = UNKNOWN_NODEID; + if (!resolver->lookup_resolved_name (path.get_node_id (), &resolved_node)) + { + resolver->lookup_resolved_type (path.get_node_id (), &resolved_node); + } + + if (resolved_node == UNKNOWN_NODEID) + return; + + const CanonicalPath *type_path = nullptr; + if (mappings->lookup_canonical_path (resolved_node, &type_path)) + { + auto &final_seg = path.get_segments ().back (); + switch (final_seg->get_type ()) + { + case AST::TypePathSegment::SegmentType::GENERIC: { + AST::TypePathSegmentGeneric *s + = static_cast (final_seg.get ()); + + std::vector args; + if (s->has_generic_args ()) + { + ResolveGenericArgs::go (s->get_generic_args ()); + for (auto &generic : s->get_generic_args ().get_generic_args ()) + { + // FIXME: What do we want to do here in case there is a + // constant or an ambiguous const generic? + // TODO: At that point, will all generics have been + // disambiguated? Can we thus canonical resolve types and + // const and `gcc_unreachable` on ambiguous types? + // This is probably fine as we just want to canonicalize + // types, right? + if (generic.get_kind () == AST::GenericArg::Kind::Type) + { + CanonicalPath arg = CanonicalPath::create_empty (); + bool ok = ResolveTypeToCanonicalPath::go ( + generic.get_type ().get (), arg); + if (ok) + args.push_back (std::move (arg)); + } + } + } + + result = *type_path; + if (!args.empty ()) + { + // append this onto the path + std::string buf; + for (size_t i = 0; i < args.size (); i++) + { + bool has_next = (i + 1) < args.size (); + const auto &arg = args.at (i); + + buf += arg.get (); + if (has_next) + buf += ", "; + } + + std::string arg_seg = "<" + buf + ">"; + CanonicalPath argument_seg + = CanonicalPath::new_seg (s->get_node_id (), arg_seg); + result = result.append (argument_seg); + } + } + break; + + default: + result = *type_path; + break; + } + } +} + +void +ResolveTypeToCanonicalPath::visit (AST::ReferenceType &type) +{ + CanonicalPath path = CanonicalPath::create_empty (); + bool ok + = ResolveTypeToCanonicalPath::go (type.get_type_referenced ().get (), path); + if (ok) + { + std::string ref_type_str = type.is_mut () ? "mut" : ""; + std::string ref_path = "&" + ref_type_str + " " + path.get (); + result = CanonicalPath::new_seg (type.get_node_id (), ref_path); + } +} + +void +ResolveTypeToCanonicalPath::visit (AST::RawPointerType &type) +{ + CanonicalPath path = CanonicalPath::create_empty (); + bool ok + = ResolveTypeToCanonicalPath::go (type.get_type_pointed_to ().get (), path); + if (ok) + { + std::string ptr_type_str + = type.get_pointer_type () == AST::RawPointerType::CONST ? "const" + : "mut"; + std::string ptr_path = "*" + ptr_type_str + " " + path.get (); + result = CanonicalPath::new_seg (type.get_node_id (), ptr_path); + } +} + +void +ResolveTypeToCanonicalPath::visit (AST::SliceType &type) +{ + CanonicalPath path = CanonicalPath::create_empty (); + bool ok = ResolveTypeToCanonicalPath::go (type.get_elem_type ().get (), path); + if (ok) + { + std::string slice_path = "[" + path.get () + "]"; + result = CanonicalPath::new_seg (type.get_node_id (), slice_path); + } +} + +void +ResolveTypeToCanonicalPath::visit (AST::TraitObjectTypeOneBound &type) +{ + CanonicalPath path = CanonicalPath::create_empty (); + bool ok + = ResolveTypeToCanonicalPath::go (&type.get_trait_bound ().get_type_path (), + path); + if (ok) + { + std::string slice_path = ""; + result = CanonicalPath::new_seg (type.get_node_id (), slice_path); + } +} + +void +ResolveTypeToCanonicalPath::visit (AST::TraitObjectType &type) +{ + // FIXME is this actually allowed? dyn A+B + gcc_unreachable (); +} + +ResolveTypeToCanonicalPath::ResolveTypeToCanonicalPath () + : ResolverBase (), result (CanonicalPath::create_empty ()) +{} + +bool +ResolveGenericArgs::is_const_value_name (const CanonicalPath &path) +{ + NodeId resolved; + auto found = resolver->get_name_scope ().lookup (path, &resolved); + + return found; +} + +bool +ResolveGenericArgs::is_type_name (const CanonicalPath &path) +{ + NodeId resolved; + auto found = resolver->get_type_scope ().lookup (path, &resolved); + + return found; +} + +void +ResolveGenericArgs::disambiguate (AST::GenericArg &arg) +{ + auto path = canonical_prefix.append ( + CanonicalPath::new_seg (UNKNOWN_NODEID, arg.get_path ())); + + auto is_type = is_type_name (path); + auto is_value = is_const_value_name (path); + + // In case we cannot find anything, we resolve the ambiguity to a type. + // This causes the typechecker to error out properly and when necessary. + // But types also take priority over const values in the case of + // ambiguities, hence the weird control flow + if (is_type || (!is_type && !is_value)) + arg = arg.disambiguate_to_type (); + else if (is_value) + arg = arg.disambiguate_to_const (); +} + +void +ResolveGenericArgs::resolve_disambiguated_generic (AST::GenericArg &arg) +{ + switch (arg.get_kind ()) + { + case AST::GenericArg::Kind::Const: + ResolveExpr::go (arg.get_expression ().get (), prefix, canonical_prefix); + break; + case AST::GenericArg::Kind::Type: + ResolveType::go (arg.get_type ().get ()); + break; + default: + gcc_unreachable (); + } +} +void +ResolveGenericArgs::go (AST::GenericArgs &generic_args) +{ + auto empty = CanonicalPath::create_empty (); + + go (generic_args, empty, empty); +} + +void +ResolveGenericArgs::go (AST::GenericArgs &generic_args, + const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) +{ + auto resolver = ResolveGenericArgs (prefix, canonical_prefix); + + for (auto &arg : generic_args.get_generic_args ()) + { + if (arg.get_kind () == AST::GenericArg::Kind::Either) + resolver.disambiguate (arg); + + resolver.resolve_disambiguated_generic (arg); + } +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h new file mode 100644 index 00000000000..5a71268c0d4 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-type.h @@ -0,0 +1,290 @@ +// 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_RESOLVE_TYPE_H +#define RUST_AST_RESOLVE_TYPE_H + +#include "rust-ast-resolve-base.h" +#include "rust-ast-resolve-expr.h" +#include "rust-ast-full.h" + +namespace Rust { +namespace Resolver { + +class ResolveRelativeTypePath +{ +public: + static bool go (AST::TypePath &path, NodeId &resolved_node_id); +}; + +class ResolveRelativeQualTypePath : public ResolverBase +{ + using ResolverBase::visit; + +public: + static bool go (AST::QualifiedPathInType &path); + + void visit (AST::TypePathSegmentGeneric &seg) override; + + void visit (AST::TypePathSegment &seg) override; + +protected: + bool resolve_qual_seg (AST::QualifiedPathType &seg); + +private: + ResolveRelativeQualTypePath (); + + bool failure_flag; +}; + +class ResolveType : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static NodeId go (AST::Type *type) + { + ResolveType resolver; + type->accept_vis (resolver); + return resolver.resolved_node; + } + + void visit (AST::BareFunctionType &fntype) override + { + for (auto ¶m : fntype.get_function_params ()) + ResolveType::go (param.get_type ().get ()); + + if (fntype.has_return_type ()) + ResolveType::go (fntype.get_return_type ().get ()); + } + + void visit (AST::TupleType &tuple) override + { + if (tuple.is_unit_type ()) + { + resolved_node = resolver->get_unit_type_node_id (); + return; + } + + for (auto &elem : tuple.get_elems ()) + ResolveType::go (elem.get ()); + } + + void visit (AST::TypePath &path) override + { + ResolveRelativeTypePath::go (path, resolved_node); + } + + void visit (AST::QualifiedPathInType &path) override + { + ResolveRelativeQualTypePath::go (path); + } + + void visit (AST::ArrayType &type) override; + + void visit (AST::ReferenceType &type) override; + + void visit (AST::InferredType &type) override; + + void visit (AST::NeverType &type) override; + + void visit (AST::RawPointerType &type) override; + + void visit (AST::TraitObjectTypeOneBound &type) override; + + void visit (AST::TraitObjectType &type) override; + + void visit (AST::SliceType &type) override; + +private: + ResolveType () : ResolverBase () {} +}; + +class ResolveTypeBound : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static NodeId go (AST::TypeParamBound *type) + { + ResolveTypeBound resolver; + type->accept_vis (resolver); + return resolver.resolved_node; + }; + + void visit (AST::TraitBound &bound) override + { + resolved_node = ResolveType::go (&bound.get_type_path ()); + } + +private: + ResolveTypeBound () : ResolverBase () {} +}; + +class ResolveGenericParam : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static NodeId go (AST::GenericParam *param, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) + { + ResolveGenericParam resolver (prefix, canonical_prefix); + param->accept_vis (resolver); + return resolver.resolved_node; + } + + void visit (AST::ConstGenericParam ¶m) override + { + ResolveType::go (param.get_type ().get ()); + + if (param.has_default_value ()) + ResolveExpr::go (param.get_default_value ().get_expression ().get (), + prefix, canonical_prefix); + + ok = true; + } + + void visit (AST::TypeParam ¶m) override + { + // if it has a type lets resolve it + if (param.has_type ()) + ResolveType::go (param.get_type ().get ()); + + if (param.has_type_param_bounds ()) + { + for (auto &bound : param.get_type_param_bounds ()) + { + ResolveTypeBound::go (bound.get ()); + } + } + + auto seg = CanonicalPath::new_seg (param.get_node_id (), + param.get_type_representation ()); + resolver->get_type_scope ().insert ( + seg, param.get_node_id (), param.get_locus (), false, + [&] (const CanonicalPath &, NodeId, Location locus) -> void { + rust_error_at (param.get_locus (), + "generic param redefined multiple times"); + rust_error_at (locus, "was defined here"); + }); + + mappings->insert_canonical_path (param.get_node_id (), seg); + } + +private: + ResolveGenericParam (const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) + : ResolverBase (), ok (false), prefix (prefix), + canonical_prefix (canonical_prefix) + {} + + bool ok; + const CanonicalPath &prefix; + const CanonicalPath &canonical_prefix; +}; + +class ResolveWhereClause : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static void Resolve (AST::WhereClause &where_clause) + { + ResolveWhereClause r; + for (auto &clause : where_clause.get_items ()) + clause->accept_vis (r); + } + + void visit (AST::TypeBoundWhereClauseItem &item) override + { + ResolveType::go (item.get_type ().get ()); + if (item.has_type_param_bounds ()) + { + for (auto &bound : item.get_type_param_bounds ()) + { + ResolveTypeBound::go (bound.get ()); + } + } + } + +private: + ResolveWhereClause () : ResolverBase () {} +}; + +class ResolveTypeToCanonicalPath : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static bool go (AST::Type *type, CanonicalPath &result); + + void visit (AST::TypePath &path) override; + + void visit (AST::ReferenceType &type) override; + + void visit (AST::RawPointerType &type) override; + + void visit (AST::SliceType &type) override; + + void visit (AST::TraitObjectTypeOneBound &type) override; + + void visit (AST::TraitObjectType &type) override; + +private: + ResolveTypeToCanonicalPath (); + + CanonicalPath result; +}; + +class ResolveGenericArgs : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static void go (AST::GenericArgs &generic_args); + static void go (AST::GenericArgs &generic_args, const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix); + +private: + ResolveGenericArgs (const CanonicalPath &prefix, + const CanonicalPath &canonical_prefix) + : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix) + {} + + bool is_type_name (const CanonicalPath &path); + bool is_const_value_name (const CanonicalPath &path); + + /** + * Resolve a disambiguated generic arg + */ + void disambiguate (AST::GenericArg &arg); + + /** + * Resolve a disambiguated generic arg + */ + void resolve_disambiguated_generic (AST::GenericArg &arg); + + const CanonicalPath &prefix; + const CanonicalPath &canonical_prefix; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_AST_RESOLVE_TYPE_H diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc new file mode 100644 index 00000000000..93fa7c8761c --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve.cc @@ -0,0 +1,115 @@ +// 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 +// . + +#include "rust-ast-resolve.h" +#include "rust-ast-full.h" +#include "rust-tyty.h" +#include "rust-ast-resolve-toplevel.h" +#include "rust-ast-resolve-item.h" +#include "rust-ast-resolve-expr.h" +#include "rust-ast-resolve-struct-expr-field.h" + +extern bool +saw_errors (void); + +namespace Rust { +namespace Resolver { + +// NameResolution + +NameResolution * +NameResolution::get () +{ + static NameResolution *instance; + if (instance == nullptr) + instance = new NameResolution (); + + return instance; +} + +NameResolution::NameResolution () + : resolver (Resolver::get ()), mappings (Analysis::Mappings::get ()) +{ + // these are global + resolver->get_type_scope ().push (mappings->get_next_node_id ()); + resolver->insert_builtin_types (resolver->get_type_scope ().peek ()); + resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); +} + +void +NameResolution::Resolve (AST::Crate &crate) +{ + auto resolver = get (); + resolver->go (crate); +} + +void +NameResolution::go (AST::Crate &crate) +{ + // lookup current crate name + CrateNum cnum = mappings->get_current_crate (); + std::string crate_name; + bool ok = mappings->get_crate_name (cnum, crate_name); + rust_assert (ok); + + // setup the ribs + NodeId scope_node_id = crate.get_node_id (); + resolver->get_name_scope ().push (scope_node_id); + resolver->get_type_scope ().push (scope_node_id); + resolver->get_label_scope ().push (scope_node_id); + resolver->push_new_name_rib (resolver->get_name_scope ().peek ()); + resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); + resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + + // get the root segment + CanonicalPath crate_prefix + = CanonicalPath::new_seg (scope_node_id, crate_name); + crate_prefix.set_crate_num (cnum); + + // setup a dummy crate node + resolver->get_name_scope ().insert ( + CanonicalPath::new_seg (crate.get_node_id (), "__$$crate__"), + crate.get_node_id (), Location ()); + + // setup the root scope + resolver->push_new_module_scope (scope_node_id); + + // first gather the top-level namespace names then we drill down so this + // allows for resolving forward declarations since an impl block might have + // a Self type Foo which is defined after the impl block for example. + for (auto it = crate.items.begin (); it != crate.items.end (); it++) + ResolveTopLevel::go (it->get (), CanonicalPath::create_empty (), + crate_prefix); + + // FIXME remove this + if (saw_errors ()) + { + resolver->pop_module_scope (); + return; + } + + // next we can drill down into the items and their scopes + for (auto it = crate.items.begin (); it != crate.items.end (); it++) + ResolveItem::go (it->get (), CanonicalPath::create_empty (), crate_prefix); + + // done + resolver->pop_module_scope (); +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/resolve/rust-ast-resolve.h b/gcc/rust/resolve/rust-ast-resolve.h new file mode 100644 index 00000000000..a2e10d5c742 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve.h @@ -0,0 +1,50 @@ +// 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_RESOLVE_H +#define RUST_AST_RESOLVE_H + +#include "rust-name-resolver.h" +#include "rust-ast-full.h" +#include "rust-hir-map.h" + +namespace Rust { +namespace Resolver { + +class NameResolution +{ +public: + static void Resolve (AST::Crate &crate); + + static NameResolution *get (); + + ~NameResolution () {} + +private: + void go (AST::Crate &crate); + + NameResolution (); + + Resolver *resolver; + Analysis::Mappings *mappings; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_AST_RESOLVE_H diff --git a/gcc/rust/resolve/rust-ast-verify-assignee.h b/gcc/rust/resolve/rust-ast-verify-assignee.h new file mode 100644 index 00000000000..74551cb014d --- /dev/null +++ b/gcc/rust/resolve/rust-ast-verify-assignee.h @@ -0,0 +1,84 @@ +// 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_VERIFY_ASSIGNEE +#define RUST_AST_VERIFY_ASSIGNEE + +#include "rust-ast-resolve-base.h" +#include "rust-ast-full.h" + +namespace Rust { +namespace Resolver { + +class VerifyAsignee : public ResolverBase +{ + using Rust::Resolver::ResolverBase::visit; + +public: + static bool go (AST::Expr *assignee, NodeId parent) + { + VerifyAsignee checker (parent); + assignee->accept_vis (checker); + if (!checker.ok) + rust_error_at (assignee->get_locus (), + "invalid left-hand side of assignment"); + return checker.ok; + } + + void visit (AST::ArrayIndexExpr &expr) override + { + expr.get_array_expr ()->accept_vis (*this); + } + + void visit (AST::FieldAccessExpr &expr) override + { + expr.get_receiver_expr ()->accept_vis (*this); + } + + void visit (AST::TupleIndexExpr &expr) override + { + expr.get_tuple_expr ()->accept_vis (*this); + } + + void visit (AST::IdentifierExpr &expr) override + { + if (!resolver->get_name_scope ().lookup ( + CanonicalPath::new_seg (expr.get_node_id (), expr.as_string ()), + &resolved_node)) + return; + + ok = true; + } + + void visit (AST::DereferenceExpr &expr) override + { + expr.get_dereferenced_expr ()->accept_vis (*this); + } + + void visit (AST::PathInExpression &expr) override { ok = true; } + +private: + VerifyAsignee (NodeId parent) : ResolverBase (), ok (false) {} + + bool ok; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_AST_VERIFY_ASSIGNEE diff --git a/gcc/rust/resolve/rust-name-resolver.cc b/gcc/rust/resolve/rust-name-resolver.cc new file mode 100644 index 00000000000..fb7087425c1 --- /dev/null +++ b/gcc/rust/resolve/rust-name-resolver.cc @@ -0,0 +1,503 @@ +// 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 +// . + +#include "rust-name-resolver.h" +#include "rust-ast-full.h" + +#define MKBUILTIN_TYPE(_X, _R, _TY) \ + do \ + { \ + AST::PathIdentSegment seg (_X, Linemap::predeclared_location ()); \ + auto typePath = ::std::unique_ptr ( \ + new AST::TypePathSegment (::std::move (seg), false, \ + Linemap::predeclared_location ())); \ + ::std::vector< ::std::unique_ptr > segs; \ + segs.push_back (::std::move (typePath)); \ + auto builtin_type \ + = new AST::TypePath (::std::move (segs), \ + Linemap::predeclared_location (), false); \ + _R.push_back (builtin_type); \ + tyctx->insert_builtin (_TY->get_ref (), builtin_type->get_node_id (), \ + _TY); \ + mappings->insert_node_to_hir (builtin_type->get_node_id (), \ + _TY->get_ref ()); \ + mappings->insert_canonical_path ( \ + builtin_type->get_node_id (), \ + CanonicalPath::new_seg (builtin_type->get_node_id (), _X)); \ + } \ + while (0) + +namespace Rust { +namespace Resolver { + +Rib::Rib (CrateNum crateNum, NodeId node_id) + : crate_num (crateNum), node_id (node_id), + mappings (Analysis::Mappings::get ()) +{} + +void +Rib::insert_name ( + const CanonicalPath &path, NodeId id, Location locus, bool shadow, + std::function dup_cb) +{ + auto it = path_mappings.find (path); + bool path_already_exists = it != path_mappings.end (); + if (path_already_exists && !shadow) + { + const auto &decl = decls_within_rib.find (it->second); + if (decl != decls_within_rib.end ()) + dup_cb (path, it->second, decl->second); + else + dup_cb (path, it->second, locus); + + return; + } + + path_mappings[path] = id; + reverse_path_mappings.insert (std::pair (id, path)); + decls_within_rib.insert (std::pair (id, locus)); + references[id] = {}; +} + +bool +Rib::lookup_name (const CanonicalPath &ident, NodeId *id) +{ + auto it = path_mappings.find (ident); + if (it == path_mappings.end ()) + return false; + + *id = it->second; + return true; +} + +void +Rib::clear_name (const CanonicalPath &ident, NodeId id) +{ + auto ii = path_mappings.find (ident); + if (ii != path_mappings.end ()) + path_mappings.erase (ii); + + auto ij = reverse_path_mappings.find (id); + if (ij != reverse_path_mappings.end ()) + reverse_path_mappings.erase (ij); + + auto ik = decls_within_rib.find (id); + if (ik != decls_within_rib.end ()) + decls_within_rib.erase (ik); +} + +void +Rib::append_reference_for_def (NodeId def, NodeId ref) +{ + references[def].insert (ref); +} + +bool +Rib::have_references_for_node (NodeId def) const +{ + auto it = references.find (def); + if (it == references.end ()) + return false; + + return !it->second.empty (); +} + +bool +Rib::decl_was_declared_here (NodeId def) const +{ + for (auto &it : decls_within_rib) + { + if (it.first == def) + return true; + } + return false; +} + +void +Rib::debug () const +{ + fprintf (stderr, "%s\n", debug_str ().c_str ()); +} + +std::string +Rib::debug_str () const +{ + std::string buffer; + for (const auto &it : path_mappings) + { + buffer += it.first.get () + "=" + std::to_string (it.second); + buffer += ","; + } + return "{" + buffer + "}"; +} + +Scope::Scope (CrateNum crate_num) : crate_num (crate_num) {} + +void +Scope::insert ( + const CanonicalPath &ident, NodeId id, Location locus, bool shadow, + std::function dup_cb) +{ + peek ()->insert_name (ident, id, locus, shadow, dup_cb); +} + +void +Scope::insert (const CanonicalPath &ident, NodeId id, Location locus) +{ + peek ()->insert_name (ident, id, locus, true, + [] (const CanonicalPath &, NodeId, Location) -> void { + }); +} + +bool +Scope::lookup (const CanonicalPath &ident, NodeId *id) +{ + NodeId lookup = UNKNOWN_NODEID; + iterate ([&] (Rib *r) mutable -> bool { + if (r->lookup_name (ident, &lookup)) + return false; + return true; + }); + + *id = lookup; + return lookup != UNKNOWN_NODEID; +} + +void +Scope::iterate (std::function cb) +{ + for (auto it = stack.rbegin (); it != stack.rend (); ++it) + { + if (!cb (*it)) + return; + } +} + +void +Scope::iterate (std::function cb) const +{ + for (auto it = stack.rbegin (); it != stack.rend (); ++it) + { + if (!cb (*it)) + return; + } +} + +Rib * +Scope::peek () +{ + return stack.back (); +} + +void +Scope::push (NodeId id) +{ + stack.push_back (new Rib (get_crate_num (), id)); +} + +Rib * +Scope::pop () +{ + Rib *r = peek (); + stack.pop_back (); + return r; +} + +void +Scope::append_reference_for_def (NodeId refId, NodeId defId) +{ + bool ok = false; + iterate ([&] (Rib *r) mutable -> bool { + if (r->decl_was_declared_here (defId)) + { + ok = true; + r->append_reference_for_def (defId, refId); + } + return true; + }); + rust_assert (ok); +} + +bool +Scope::decl_was_declared_here (NodeId def) const +{ + bool found = false; + iterate ([&] (const Rib *r) -> bool { + if (r->decl_was_declared_here (def)) + { + found = true; + return false; + } + return true; + }); + return found; +} + +Resolver::Resolver () + : mappings (Analysis::Mappings::get ()), tyctx (TypeCheckContext::get ()), + name_scope (Scope (mappings->get_current_crate ())), + type_scope (Scope (mappings->get_current_crate ())), + label_scope (Scope (mappings->get_current_crate ())), + macro_scope (Scope (mappings->get_current_crate ())), + global_type_node_id (UNKNOWN_NODEID), unit_ty_node_id (UNKNOWN_NODEID) +{ + generate_builtins (); +} + +Resolver * +Resolver::get () +{ + static Resolver *instance; + if (instance == nullptr) + instance = new Resolver (); + + return instance; +} + +void +Resolver::push_new_name_rib (Rib *r) +{ + rust_assert (name_ribs.find (r->get_node_id ()) == name_ribs.end ()); + name_ribs[r->get_node_id ()] = r; +} + +void +Resolver::push_new_type_rib (Rib *r) +{ + if (type_ribs.size () == 0) + global_type_node_id = r->get_node_id (); + + rust_assert (type_ribs.find (r->get_node_id ()) == type_ribs.end ()); + type_ribs[r->get_node_id ()] = r; +} + +void +Resolver::push_new_label_rib (Rib *r) +{ + rust_assert (label_ribs.find (r->get_node_id ()) == label_ribs.end ()); + label_ribs[r->get_node_id ()] = r; +} + +void +Resolver::push_new_macro_rib (Rib *r) +{ + rust_assert (label_ribs.find (r->get_node_id ()) == label_ribs.end ()); + macro_ribs[r->get_node_id ()] = r; +} + +bool +Resolver::find_name_rib (NodeId id, Rib **rib) +{ + auto it = name_ribs.find (id); + if (it == name_ribs.end ()) + return false; + + *rib = it->second; + return true; +} + +bool +Resolver::find_type_rib (NodeId id, Rib **rib) +{ + auto it = type_ribs.find (id); + if (it == type_ribs.end ()) + return false; + + *rib = it->second; + return true; +} + +bool +Resolver::find_macro_rib (NodeId id, Rib **rib) +{ + auto it = macro_ribs.find (id); + if (it == macro_ribs.end ()) + return false; + + *rib = it->second; + return true; +} + +void +Resolver::insert_builtin_types (Rib *r) +{ + auto builtins = get_builtin_types (); + for (auto &builtin : builtins) + { + CanonicalPath builtin_path + = CanonicalPath::new_seg (builtin->get_node_id (), + builtin->as_string ()); + r->insert_name (builtin_path, builtin->get_node_id (), + Linemap::predeclared_location (), false, + [] (const CanonicalPath &, NodeId, Location) -> void {}); + } +} + +std::vector & +Resolver::get_builtin_types () +{ + return builtins; +} + +void +Resolver::generate_builtins () +{ + auto u8 + = new TyTy::UintType (mappings->get_next_hir_id (), TyTy::UintType::U8); + auto u16 + = new TyTy::UintType (mappings->get_next_hir_id (), TyTy::UintType::U16); + auto u32 + = new TyTy::UintType (mappings->get_next_hir_id (), TyTy::UintType::U32); + auto u64 + = new TyTy::UintType (mappings->get_next_hir_id (), TyTy::UintType::U64); + auto u128 + = new TyTy::UintType (mappings->get_next_hir_id (), TyTy::UintType::U128); + auto i8 = new TyTy::IntType (mappings->get_next_hir_id (), TyTy::IntType::I8); + auto i16 + = new TyTy::IntType (mappings->get_next_hir_id (), TyTy::IntType::I16); + auto i32 + = new TyTy::IntType (mappings->get_next_hir_id (), TyTy::IntType::I32); + auto i64 + = new TyTy::IntType (mappings->get_next_hir_id (), TyTy::IntType::I64); + auto i128 + = new TyTy::IntType (mappings->get_next_hir_id (), TyTy::IntType::I128); + auto rbool = new TyTy::BoolType (mappings->get_next_hir_id ()); + auto f32 + = new TyTy::FloatType (mappings->get_next_hir_id (), TyTy::FloatType::F32); + auto f64 + = new TyTy::FloatType (mappings->get_next_hir_id (), TyTy::FloatType::F64); + auto usize = new TyTy::USizeType (mappings->get_next_hir_id ()); + auto isize = new TyTy::ISizeType (mappings->get_next_hir_id ()); + auto char_tyty = new TyTy::CharType (mappings->get_next_hir_id ()); + auto str = new TyTy::StrType (mappings->get_next_hir_id ()); + auto never = new TyTy::NeverType (mappings->get_next_hir_id ()); + + MKBUILTIN_TYPE ("u8", builtins, u8); + MKBUILTIN_TYPE ("u16", builtins, u16); + MKBUILTIN_TYPE ("u32", builtins, u32); + MKBUILTIN_TYPE ("u64", builtins, u64); + MKBUILTIN_TYPE ("u128", builtins, u128); + MKBUILTIN_TYPE ("i8", builtins, i8); + MKBUILTIN_TYPE ("i16", builtins, i16); + MKBUILTIN_TYPE ("i32", builtins, i32); + MKBUILTIN_TYPE ("i64", builtins, i64); + MKBUILTIN_TYPE ("i128", builtins, i128); + MKBUILTIN_TYPE ("bool", builtins, rbool); + MKBUILTIN_TYPE ("f32", builtins, f32); + MKBUILTIN_TYPE ("f64", builtins, f64); + MKBUILTIN_TYPE ("usize", builtins, usize); + MKBUILTIN_TYPE ("isize", builtins, isize); + MKBUILTIN_TYPE ("char", builtins, char_tyty); + MKBUILTIN_TYPE ("str", builtins, str); + MKBUILTIN_TYPE ("!", builtins, never); + + // unit type () + TyTy::TupleType *unit_tyty + = TyTy::TupleType::get_unit_type (mappings->get_next_hir_id ()); + std::vector > elems; + AST::TupleType *unit_type + = new AST::TupleType (std::move (elems), Linemap::predeclared_location ()); + builtins.push_back (unit_type); + tyctx->insert_builtin (unit_tyty->get_ref (), unit_type->get_node_id (), + unit_tyty); + set_unit_type_node_id (unit_type->get_node_id ()); +} + +void +Resolver::insert_resolved_name (NodeId refId, NodeId defId) +{ + resolved_names[refId] = defId; + get_name_scope ().append_reference_for_def (refId, defId); +} + +bool +Resolver::lookup_resolved_name (NodeId refId, NodeId *defId) +{ + auto it = resolved_names.find (refId); + if (it == resolved_names.end ()) + return false; + + *defId = it->second; + return true; +} + +void +Resolver::insert_resolved_type (NodeId refId, NodeId defId) +{ + // auto it = resolved_types.find (refId); + // rust_assert (it == resolved_types.end ()); + + resolved_types[refId] = defId; + get_type_scope ().append_reference_for_def (refId, defId); +} + +bool +Resolver::lookup_resolved_type (NodeId refId, NodeId *defId) +{ + auto it = resolved_types.find (refId); + if (it == resolved_types.end ()) + return false; + + *defId = it->second; + return true; +} + +void +Resolver::insert_resolved_label (NodeId refId, NodeId defId) +{ + auto it = resolved_labels.find (refId); + rust_assert (it == resolved_labels.end ()); + + resolved_labels[refId] = defId; + get_label_scope ().append_reference_for_def (refId, defId); +} + +bool +Resolver::lookup_resolved_label (NodeId refId, NodeId *defId) +{ + auto it = resolved_labels.find (refId); + if (it == resolved_labels.end ()) + return false; + + *defId = it->second; + return true; +} + +void +Resolver::insert_resolved_macro (NodeId refId, NodeId defId) +{ + auto it = resolved_macros.find (refId); + rust_assert (it == resolved_macros.end ()); + + resolved_labels[refId] = defId; + get_label_scope ().append_reference_for_def (refId, defId); +} + +bool +Resolver::lookup_resolved_macro (NodeId refId, NodeId *defId) +{ + auto it = resolved_macros.find (refId); + if (it == resolved_macros.end ()) + return false; + + *defId = it->second; + return true; +} + +} // namespace Resolver +} // namespace Rust diff --git a/gcc/rust/resolve/rust-name-resolver.h b/gcc/rust/resolve/rust-name-resolver.h new file mode 100644 index 00000000000..014628a87c9 --- /dev/null +++ b/gcc/rust/resolve/rust-name-resolver.h @@ -0,0 +1,212 @@ +// 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_NAME_RESOLVER_H +#define RUST_NAME_RESOLVER_H + +#include "rust-system.h" +#include "rust-canonical-path.h" +#include "rust-hir-map.h" +#include "rust-hir-type-check.h" + +namespace Rust { +namespace Resolver { + +class Rib +{ +public: + // Rust uses local_def_ids assigned by def_collector on the AST + // lets use NodeId instead + Rib (CrateNum crateNum, NodeId node_id); + + // this takes the relative paths of items within a compilation unit for lookup + void insert_name ( + const CanonicalPath &path, NodeId id, Location locus, bool shadow, + std::function dup_cb); + + bool lookup_canonical_path (const NodeId &id, CanonicalPath *ident); + bool lookup_name (const CanonicalPath &ident, NodeId *id); + void clear_name (const CanonicalPath &ident, NodeId id); + void append_reference_for_def (NodeId def, NodeId ref); + bool have_references_for_node (NodeId def) const; + bool decl_was_declared_here (NodeId def) const; + void debug () const; + std::string debug_str () const; + + CrateNum get_crate_num () const { return crate_num; } + NodeId get_node_id () const { return node_id; } + std::map &get_declarations () { return decls_within_rib; } + +private: + CrateNum crate_num; + NodeId node_id; + std::map path_mappings; + std::map reverse_path_mappings; + std::map decls_within_rib; + std::map> references; + Analysis::Mappings *mappings; +}; + +class Scope +{ +public: + Scope (CrateNum crate_num); + + void + insert (const CanonicalPath &ident, NodeId id, Location locus, bool shadow, + std::function dup_cb); + + void insert (const CanonicalPath &ident, NodeId id, Location locus); + bool lookup (const CanonicalPath &ident, NodeId *id); + + void iterate (std::function cb); + void iterate (std::function cb) const; + + Rib *peek (); + void push (NodeId id); + Rib *pop (); + + bool decl_was_declared_here (NodeId def) const; + void append_reference_for_def (NodeId refId, NodeId defId); + + CrateNum get_crate_num () const { return crate_num; } + +private: + CrateNum crate_num; + std::vector stack; +}; + +class Resolver +{ +public: + static Resolver *get (); + ~Resolver () {} + + // these builtin types + void insert_builtin_types (Rib *r); + + // these will be required for type resolution passes to + // map back to tyty nodes + std::vector &get_builtin_types (); + + void push_new_name_rib (Rib *r); + void push_new_type_rib (Rib *r); + void push_new_label_rib (Rib *r); + void push_new_macro_rib (Rib *r); + + bool find_name_rib (NodeId id, Rib **rib); + bool find_type_rib (NodeId id, Rib **rib); + bool find_label_rib (NodeId id, Rib **rib); + bool find_macro_rib (NodeId id, Rib **rib); + + void insert_resolved_name (NodeId refId, NodeId defId); + bool lookup_resolved_name (NodeId refId, NodeId *defId); + + void insert_resolved_type (NodeId refId, NodeId defId); + bool lookup_resolved_type (NodeId refId, NodeId *defId); + + void insert_resolved_label (NodeId refId, NodeId defId); + bool lookup_resolved_label (NodeId refId, NodeId *defId); + + void insert_resolved_macro (NodeId refId, NodeId defId); + bool lookup_resolved_macro (NodeId refId, NodeId *defId); + + // proxy for scoping + Scope &get_name_scope () { return name_scope; } + Scope &get_type_scope () { return type_scope; } + Scope &get_label_scope () { return label_scope; } + Scope &get_macro_scope () { return macro_scope; } + + NodeId get_global_type_node_id () { return global_type_node_id; } + void set_unit_type_node_id (NodeId id) { unit_ty_node_id = id; } + NodeId get_unit_type_node_id () { return unit_ty_node_id; } + + void push_new_module_scope (NodeId module_id) + { + current_module_stack.push_back (module_id); + } + + void pop_module_scope () + { + rust_assert (!current_module_stack.empty ()); + current_module_stack.pop_back (); + } + + NodeId peek_current_module_scope () const + { + rust_assert (!current_module_stack.empty ()); + return current_module_stack.back (); + } + + NodeId peek_crate_module_scope () const + { + rust_assert (!current_module_stack.empty ()); + return current_module_stack.front (); + } + + NodeId peek_parent_module_scope () const + { + rust_assert (current_module_stack.size () > 1); + return current_module_stack.at (current_module_stack.size () - 2); + } + +private: + Resolver (); + + void generate_builtins (); + + Analysis::Mappings *mappings; + TypeCheckContext *tyctx; + + std::vector builtins; + + Scope name_scope; + Scope type_scope; + Scope label_scope; + Scope macro_scope; + + NodeId global_type_node_id; + NodeId unit_ty_node_id; + + // map a AST Node to a Rib + std::map name_ribs; + std::map type_ribs; + std::map label_ribs; + std::map macro_ribs; + + // Rust uses DefIds to namespace these under a crate_num + // but then it uses the def_collector to assign local_defids + // to each ast node as well. not sure if this is going to fit + // with gcc very well to compile a full crate in one go but we will + // see. + + // these are of the form ref->Def-NodeId + // we need two namespaces one for names and ones for types + std::map resolved_names; + std::map resolved_types; + std::map resolved_labels; + std::map resolved_macros; + + // keep track of the current module scope ids + std::vector current_module_stack; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_NAME_RESOLVER_H From patchwork Wed Aug 24 11:59:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56994 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 2811A396DC11 for ; Wed, 24 Aug 2022 12:05:15 +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 5E265388550D; Wed, 24 Aug 2022 12:00:53 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 5E265388550D Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x435.google.com with SMTP id u5so12679597wrt.11; Wed, 24 Aug 2022 05:00:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=8bHf1rFalr6TgcpymkFv6bNxUya4sUaKWzBlfOAjfzY=; b=ba+2r0si27ButZl89QFpKuPsE3j6XdhG8qHkut8quitD3BZfTORnCnv9kwc3nHsUpr CLnuft8sg+mR8ZWhvfhM+P6ZHTvrqGXEvL/BDHO9mkaC07wGHrKm1nigpYucKmT3x69g 39fsaFXxovn7STn34dXxjQWrbYKITK7ajqjh4IRCFn54Sg2+KD0FPH9KSl5yj1jQPbQD es2vqkIMnrWk8AgI6uetJtMMVJ6doVSymzsk6GZFtRMAzxEWzQk7eYQwJjqBrjhJJsQo A0X3TDVw1EXT8KJRVpT8d2JPHfR7t7yQYVIbZVb341qVga0Cv86IyBe0XffXCjjO0KFp ojEw== 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; bh=8bHf1rFalr6TgcpymkFv6bNxUya4sUaKWzBlfOAjfzY=; b=1NdLZ9oDYujdPQoZ1V4l129prmRHxICHPWlxQ8CBN4AbA+DKCIDMckG21Jf1x3PWsr ulNpjPB1mrCgrsrFPs0tT3oZHcSQU84CkXa8IvxMeibS/kEEJr0k8WXegz/39b5MQwKD s8Eg6fryDqCDF47jT4AqoGsrrTG4RmMtkQt9vO+FNMkyfuEpXZdTtxYzZRSo5kLReCmf 2fJtIfqmZCEMNhSISoQ+yC7SI5BlUb33w8ywJ+k8ertDCmLPDbjW8yCjBp7YZYEdD9fz wNDl7Ut6sNU2KNl/WVT/Mzdy5KFrsEs7sNQYEa4phBKz3NEP1LDNom9S2I+fhJX2puQZ fUqA== X-Gm-Message-State: ACgBeo20epypnQmp5eFyEvxF6RcoYxIA+au9JNmQ1FH4trda9kuRSsFP ycyXZZQF0zJaCUB56K4nEW5FNPMSKGk= X-Google-Smtp-Source: AA6agR6C8v6F0lVZFq6E/UUKeVER1KpcJBb3EtHgr6CRxP6rRbRhsviiSVfyPOSbW10msubN5N5WYw== X-Received: by 2002:a5d:4a43:0:b0:225:385d:db05 with SMTP id v3-20020a5d4a43000000b00225385ddb05mr12730899wrs.504.1661342450558; Wed, 24 Aug 2022 05:00:50 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:48 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 14/37] gccrs: Add AST to HIR lowering pass Date: Wed, 24 Aug 2022 12:59:33 +0100 Message-Id: <20220824115956.737931-15-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron This performs the lowering of the AST to HIR the interesting piece here is that we desugar alot of the AST like we mentioned in the previous pass, but crucially we strip out all code that is "marked-for-strip" which failed cfg-expansion from the expansion pass. So now the HIR includes all code required to compile for this crate. --- gcc/rust/hir/rust-ast-lower-base.cc | 1078 +++++++++++++++++ gcc/rust/hir/rust-ast-lower-base.h | 297 +++++ gcc/rust/hir/rust-ast-lower-block.h | 230 ++++ gcc/rust/hir/rust-ast-lower-enumitem.h | 181 +++ gcc/rust/hir/rust-ast-lower-expr.h | 766 ++++++++++++ gcc/rust/hir/rust-ast-lower-extern.h | 121 ++ gcc/rust/hir/rust-ast-lower-implitem.h | 521 ++++++++ gcc/rust/hir/rust-ast-lower-item.cc | 741 +++++++++++ gcc/rust/hir/rust-ast-lower-item.h | 78 ++ gcc/rust/hir/rust-ast-lower-pattern.cc | 229 ++++ gcc/rust/hir/rust-ast-lower-pattern.h | 72 ++ gcc/rust/hir/rust-ast-lower-stmt.h | 418 +++++++ .../hir/rust-ast-lower-struct-field-expr.h | 63 + gcc/rust/hir/rust-ast-lower-type.h | 532 ++++++++ gcc/rust/hir/rust-ast-lower.cc | 477 ++++++++ gcc/rust/hir/rust-ast-lower.h | 59 + gcc/rust/hir/rust-hir-dump.cc | 521 ++++++++ gcc/rust/hir/rust-hir-dump.h | 193 +++ 18 files changed, 6577 insertions(+) create mode 100644 gcc/rust/hir/rust-ast-lower-base.cc create mode 100644 gcc/rust/hir/rust-ast-lower-base.h create mode 100644 gcc/rust/hir/rust-ast-lower-block.h create mode 100644 gcc/rust/hir/rust-ast-lower-enumitem.h create mode 100644 gcc/rust/hir/rust-ast-lower-expr.h create mode 100644 gcc/rust/hir/rust-ast-lower-extern.h create mode 100644 gcc/rust/hir/rust-ast-lower-implitem.h create mode 100644 gcc/rust/hir/rust-ast-lower-item.cc create mode 100644 gcc/rust/hir/rust-ast-lower-item.h create mode 100644 gcc/rust/hir/rust-ast-lower-pattern.cc create mode 100644 gcc/rust/hir/rust-ast-lower-pattern.h create mode 100644 gcc/rust/hir/rust-ast-lower-stmt.h create mode 100644 gcc/rust/hir/rust-ast-lower-struct-field-expr.h create mode 100644 gcc/rust/hir/rust-ast-lower-type.h create mode 100644 gcc/rust/hir/rust-ast-lower.cc create mode 100644 gcc/rust/hir/rust-ast-lower.h create mode 100644 gcc/rust/hir/rust-hir-dump.cc create mode 100644 gcc/rust/hir/rust-hir-dump.h diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc new file mode 100644 index 00000000000..a67461791d7 --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower-base.cc @@ -0,0 +1,1078 @@ +// 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 +// . + +#include "rust-ast-lower-base.h" +#include "rust-ast-lower-type.h" +#include "rust-ast-lower-pattern.h" +#include "rust-ast-lower-extern.h" + +namespace Rust { +namespace HIR { + +void +ASTLoweringBase::visit (AST::Token &tok) +{} +void +ASTLoweringBase::visit (AST::DelimTokenTree &delim_tok_tree) +{} +void +ASTLoweringBase::visit (AST::AttrInputMetaItemContainer &input) +{} +// void ASTLoweringBase::visit(MetaItem& meta_item) {} +// void vsit(Stmt& stmt) {} +// void ASTLoweringBase::visit(Expr& expr) {} +void +ASTLoweringBase::visit (AST::IdentifierExpr &ident_expr) +{} +// void ASTLoweringBase::visit(Pattern& pattern) {} +// void ASTLoweringBase::visit(Type& type) {} +// void ASTLoweringBase::visit(TypeParamBound& type_param_bound) {} +void +ASTLoweringBase::visit (AST::Lifetime &lifetime) +{} +// void ASTLoweringBase::visit(GenericParam& generic_param) {} +void +ASTLoweringBase::visit (AST::LifetimeParam &lifetime_param) +{} +void +ASTLoweringBase::visit (AST::ConstGenericParam &const_param) +{} +// void ASTLoweringBase::visit(TraitItem& trait_item) {} +// void ASTLoweringBase::visit(InherentImplItem& inherent_impl_item) {} +// void ASTLoweringBase::visit(TraitImplItem& trait_impl_item) {} + +// rust-path.h +void +ASTLoweringBase::visit (AST::PathInExpression &path) +{} +void +ASTLoweringBase::visit (AST::TypePathSegment &segment) +{} +void +ASTLoweringBase::visit (AST::TypePathSegmentGeneric &segment) +{} +void +ASTLoweringBase::visit (AST::TypePathSegmentFunction &segment) +{} +void +ASTLoweringBase::visit (AST::TypePath &path) +{} +void +ASTLoweringBase::visit (AST::QualifiedPathInExpression &path) +{} +void +ASTLoweringBase::visit (AST::QualifiedPathInType &path) +{} + +// rust-expr.h +void +ASTLoweringBase::visit (AST::LiteralExpr &expr) +{} +void +ASTLoweringBase::visit (AST::AttrInputLiteral &attr_input) +{} +void +ASTLoweringBase::visit (AST::MetaItemLitExpr &meta_item) +{} +void +ASTLoweringBase::visit (AST::MetaItemPathLit &meta_item) +{} +void +ASTLoweringBase::visit (AST::BorrowExpr &expr) +{} +void +ASTLoweringBase::visit (AST::DereferenceExpr &expr) +{} +void +ASTLoweringBase::visit (AST::ErrorPropagationExpr &expr) +{} +void +ASTLoweringBase::visit (AST::NegationExpr &expr) +{} +void +ASTLoweringBase::visit (AST::ArithmeticOrLogicalExpr &expr) +{} +void +ASTLoweringBase::visit (AST::ComparisonExpr &expr) +{} +void +ASTLoweringBase::visit (AST::LazyBooleanExpr &expr) +{} +void +ASTLoweringBase::visit (AST::TypeCastExpr &expr) +{} +void +ASTLoweringBase::visit (AST::AssignmentExpr &expr) +{} +void +ASTLoweringBase::visit (AST::CompoundAssignmentExpr &expr) +{} +void +ASTLoweringBase::visit (AST::GroupedExpr &expr) +{} +// void ASTLoweringBase::visit(ArrayElems& elems) {} +void +ASTLoweringBase::visit (AST::ArrayElemsValues &elems) +{} +void +ASTLoweringBase::visit (AST::ArrayElemsCopied &elems) +{} +void +ASTLoweringBase::visit (AST::ArrayExpr &expr) +{} +void +ASTLoweringBase::visit (AST::ArrayIndexExpr &expr) +{} +void +ASTLoweringBase::visit (AST::TupleExpr &expr) +{} +void +ASTLoweringBase::visit (AST::TupleIndexExpr &expr) +{} +void +ASTLoweringBase::visit (AST::StructExprStruct &expr) +{} +// void ASTLoweringBase::visit(StructExprField& field) {} +void +ASTLoweringBase::visit (AST::StructExprFieldIdentifier &field) +{} +void +ASTLoweringBase::visit (AST::StructExprFieldIdentifierValue &field) +{} +void +ASTLoweringBase::visit (AST::StructExprFieldIndexValue &field) +{} +void +ASTLoweringBase::visit (AST::StructExprStructFields &expr) +{} +void +ASTLoweringBase::visit (AST::StructExprStructBase &expr) +{} +void +ASTLoweringBase::visit (AST::CallExpr &expr) +{} +void +ASTLoweringBase::visit (AST::MethodCallExpr &expr) +{} +void +ASTLoweringBase::visit (AST::FieldAccessExpr &expr) +{} +void +ASTLoweringBase::visit (AST::ClosureExprInner &expr) +{} +void +ASTLoweringBase::visit (AST::BlockExpr &expr) +{} +void +ASTLoweringBase::visit (AST::ClosureExprInnerTyped &expr) +{} +void +ASTLoweringBase::visit (AST::ContinueExpr &expr) +{} +void +ASTLoweringBase::visit (AST::BreakExpr &expr) +{} +void +ASTLoweringBase::visit (AST::RangeFromToExpr &expr) +{} +void +ASTLoweringBase::visit (AST::RangeFromExpr &expr) +{} +void +ASTLoweringBase::visit (AST::RangeToExpr &expr) +{} +void +ASTLoweringBase::visit (AST::RangeFullExpr &expr) +{} +void +ASTLoweringBase::visit (AST::RangeFromToInclExpr &expr) +{} +void +ASTLoweringBase::visit (AST::RangeToInclExpr &expr) +{} +void +ASTLoweringBase::visit (AST::ReturnExpr &expr) +{} +void +ASTLoweringBase::visit (AST::UnsafeBlockExpr &expr) +{} +void +ASTLoweringBase::visit (AST::LoopExpr &expr) +{} +void +ASTLoweringBase::visit (AST::WhileLoopExpr &expr) +{} +void +ASTLoweringBase::visit (AST::WhileLetLoopExpr &expr) +{} +void +ASTLoweringBase::visit (AST::ForLoopExpr &expr) +{} +void +ASTLoweringBase::visit (AST::IfExpr &expr) +{} +void +ASTLoweringBase::visit (AST::IfExprConseqElse &expr) +{} +void +ASTLoweringBase::visit (AST::IfExprConseqIf &expr) +{} +void +ASTLoweringBase::visit (AST::IfExprConseqIfLet &expr) +{} +void +ASTLoweringBase::visit (AST::IfLetExpr &expr) +{} +void +ASTLoweringBase::visit (AST::IfLetExprConseqElse &expr) +{} +void +ASTLoweringBase::visit (AST::IfLetExprConseqIf &expr) +{} +void +ASTLoweringBase::visit (AST::IfLetExprConseqIfLet &expr) +{} +// void ASTLoweringBase::visit(MatchCase& match_case) {} +// void ASTLoweringBase:: (AST::MatchCaseBlockExpr &match_case) {} +// void ASTLoweringBase:: (AST::MatchCaseExpr &match_case) {} +void +ASTLoweringBase::visit (AST::MatchExpr &expr) +{} +void +ASTLoweringBase::visit (AST::AwaitExpr &expr) +{} +void +ASTLoweringBase::visit (AST::AsyncBlockExpr &expr) +{} + +// rust-item.h +void +ASTLoweringBase::visit (AST::TypeParam ¶m) +{} +// void ASTLoweringBase::visit(WhereClauseItem& item) {} +void +ASTLoweringBase::visit (AST::LifetimeWhereClauseItem &item) +{} +void +ASTLoweringBase::visit (AST::TypeBoundWhereClauseItem &item) +{} +void +ASTLoweringBase::visit (AST::Method &method) +{} +void +ASTLoweringBase::visit (AST::Module &module) +{} +void +ASTLoweringBase::visit (AST::ExternCrate &crate) +{} +// void ASTLoweringBase::visit(UseTree& use_tree) {} +void +ASTLoweringBase::visit (AST::UseTreeGlob &use_tree) +{} +void +ASTLoweringBase::visit (AST::UseTreeList &use_tree) +{} +void +ASTLoweringBase::visit (AST::UseTreeRebind &use_tree) +{} +void +ASTLoweringBase::visit (AST::UseDeclaration &use_decl) +{} +void +ASTLoweringBase::visit (AST::Function &function) +{} +void +ASTLoweringBase::visit (AST::TypeAlias &type_alias) +{} +void +ASTLoweringBase::visit (AST::StructStruct &struct_item) +{} +void +ASTLoweringBase::visit (AST::TupleStruct &tuple_struct) +{} +void +ASTLoweringBase::visit (AST::EnumItem &item) +{} +void +ASTLoweringBase::visit (AST::EnumItemTuple &item) +{} +void +ASTLoweringBase::visit (AST::EnumItemStruct &item) +{} +void +ASTLoweringBase::visit (AST::EnumItemDiscriminant &item) +{} +void +ASTLoweringBase::visit (AST::Enum &enum_item) +{} +void +ASTLoweringBase::visit (AST::Union &union_item) +{} +void +ASTLoweringBase::visit (AST::ConstantItem &const_item) +{} +void +ASTLoweringBase::visit (AST::StaticItem &static_item) +{} +void +ASTLoweringBase::visit (AST::TraitItemFunc &item) +{} +void +ASTLoweringBase::visit (AST::TraitItemMethod &item) +{} +void +ASTLoweringBase::visit (AST::TraitItemConst &item) +{} +void +ASTLoweringBase::visit (AST::TraitItemType &item) +{} +void +ASTLoweringBase::visit (AST::Trait &trait) +{} +void +ASTLoweringBase::visit (AST::InherentImpl &impl) +{} +void +ASTLoweringBase::visit (AST::TraitImpl &impl) +{} +// void ASTLoweringBase::visit(ExternalItem& item) {} +void +ASTLoweringBase::visit (AST::ExternalStaticItem &item) +{} +void +ASTLoweringBase::visit (AST::ExternalFunctionItem &item) +{} +void +ASTLoweringBase::visit (AST::ExternBlock &block) +{} + +// rust-macro.h +void +ASTLoweringBase::visit (AST::MacroMatchFragment &match) +{} +void +ASTLoweringBase::visit (AST::MacroMatchRepetition &match) +{} +void +ASTLoweringBase::visit (AST::MacroMatcher &matcher) +{} +void +ASTLoweringBase::visit (AST::MacroRulesDefinition &rules_def) +{} +void +ASTLoweringBase::visit (AST::MacroInvocation ¯o_invoc) +{} +void +ASTLoweringBase::visit (AST::MetaItemPath &meta_item) +{} +void +ASTLoweringBase::visit (AST::MetaItemSeq &meta_item) +{} +void +ASTLoweringBase::visit (AST::MetaWord &meta_item) +{} +void +ASTLoweringBase::visit (AST::MetaNameValueStr &meta_item) +{} +void +ASTLoweringBase::visit (AST::MetaListPaths &meta_item) +{} +void +ASTLoweringBase::visit (AST::MetaListNameValueStr &meta_item) +{} + +// rust-pattern.h +void +ASTLoweringBase::visit (AST::LiteralPattern &pattern) +{} +void +ASTLoweringBase::visit (AST::IdentifierPattern &pattern) +{} +void +ASTLoweringBase::visit (AST::WildcardPattern &pattern) +{} +// void ASTLoweringBase::visit(RangePatternBound& bound) {} +void +ASTLoweringBase::visit (AST::RangePatternBoundLiteral &bound) +{} +void +ASTLoweringBase::visit (AST::RangePatternBoundPath &bound) +{} +void +ASTLoweringBase::visit (AST::RangePatternBoundQualPath &bound) +{} +void +ASTLoweringBase::visit (AST::RangePattern &pattern) +{} +void +ASTLoweringBase::visit (AST::ReferencePattern &pattern) +{} +// void ASTLoweringBase::visit(StructPatternField& field) {} +void +ASTLoweringBase::visit (AST::StructPatternFieldTuplePat &field) +{} +void +ASTLoweringBase::visit (AST::StructPatternFieldIdentPat &field) +{} +void +ASTLoweringBase::visit (AST::StructPatternFieldIdent &field) +{} +void +ASTLoweringBase::visit (AST::StructPattern &pattern) +{} +// void ASTLoweringBase::visit(TupleStructItems& tuple_items) {} +void +ASTLoweringBase::visit (AST::TupleStructItemsNoRange &tuple_items) +{} +void +ASTLoweringBase::visit (AST::TupleStructItemsRange &tuple_items) +{} +void +ASTLoweringBase::visit (AST::TupleStructPattern &pattern) +{} +// void ASTLoweringBase::visit(TuplePatternItems& tuple_items) {} +void +ASTLoweringBase::visit (AST::TuplePatternItemsMultiple &tuple_items) +{} +void +ASTLoweringBase::visit (AST::TuplePatternItemsRanged &tuple_items) +{} +void +ASTLoweringBase::visit (AST::TuplePattern &pattern) +{} +void +ASTLoweringBase::visit (AST::GroupedPattern &pattern) +{} +void +ASTLoweringBase::visit (AST::SlicePattern &pattern) +{} + +// rust-stmt.h +void +ASTLoweringBase::visit (AST::EmptyStmt &stmt) +{} +void +ASTLoweringBase::visit (AST::LetStmt &stmt) +{} +void +ASTLoweringBase::visit (AST::ExprStmtWithoutBlock &stmt) +{} +void +ASTLoweringBase::visit (AST::ExprStmtWithBlock &stmt) +{} + +// rust-type.h +void +ASTLoweringBase::visit (AST::TraitBound &bound) +{} +void +ASTLoweringBase::visit (AST::ImplTraitType &type) +{} +void +ASTLoweringBase::visit (AST::TraitObjectType &type) +{} +void +ASTLoweringBase::visit (AST::ParenthesisedType &type) +{} +void +ASTLoweringBase::visit (AST::ImplTraitTypeOneBound &type) +{} +void +ASTLoweringBase::visit (AST::TraitObjectTypeOneBound &type) +{} +void +ASTLoweringBase::visit (AST::TupleType &type) +{} +void +ASTLoweringBase::visit (AST::NeverType &type) +{} +void +ASTLoweringBase::visit (AST::RawPointerType &type) +{} +void +ASTLoweringBase::visit (AST::ReferenceType &type) +{} +void +ASTLoweringBase::visit (AST::ArrayType &type) +{} +void +ASTLoweringBase::visit (AST::SliceType &type) +{} +void +ASTLoweringBase::visit (AST::InferredType &type) +{} +void +ASTLoweringBase::visit (AST::BareFunctionType &type) +{} + +HIR::Lifetime +ASTLoweringBase::lower_lifetime (AST::Lifetime &lifetime) +{ + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, lifetime.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + mappings->insert_node_to_hir (mapping.get_nodeid (), mapping.get_hirid ()); + + return HIR::Lifetime (mapping, lifetime.get_lifetime_type (), + lifetime.get_lifetime_name (), lifetime.get_locus ()); +} + +HIR::LoopLabel +ASTLoweringBase::lower_loop_label (AST::LoopLabel &loop_label) +{ + HIR::Lifetime life = lower_lifetime (loop_label.get_lifetime ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, loop_label.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + mappings->insert_node_to_hir (mapping.get_nodeid (), mapping.get_hirid ()); + + return HIR::LoopLabel (mapping, std::move (life), loop_label.get_locus ()); +} + +std::vector> +ASTLoweringBase::lower_generic_params ( + std::vector> ¶ms) +{ + std::vector> lowered; + for (auto &ast_param : params) + { + auto hir_param = ASTLowerGenericParam::translate (ast_param.get ()); + lowered.push_back (std::unique_ptr (hir_param)); + } + + return lowered; +} + +HIR::PathExprSegment +ASTLoweringBase::lower_path_expr_seg (AST::PathExprSegment &s) +{ + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, s.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + return HIR::PathExprSegment ( + std::move (mapping), + HIR::PathIdentSegment (s.get_ident_segment ().as_string ()), s.get_locus (), + s.has_generic_args () ? lower_generic_args (s.get_generic_args ()) + : HIR::GenericArgs::create_empty ()); +} + +HIR::GenericArgsBinding +ASTLoweringBase::lower_binding (AST::GenericArgsBinding &binding) +{ + HIR::Type *lowered_type + = ASTLoweringType::translate (binding.get_type ().get ()); + return HIR::GenericArgsBinding (binding.get_identifier (), + std::unique_ptr (lowered_type), + binding.get_locus ()); +} + +HIR::GenericArgs +ASTLoweringBase::lower_generic_args (AST::GenericArgs &args) +{ + std::vector binding_args; + for (auto &binding : args.get_binding_args ()) + { + HIR::GenericArgsBinding b = lower_binding (binding); + binding_args.push_back (std::move (b)); + } + + std::vector lifetime_args; + for (auto &lifetime : args.get_lifetime_args ()) + { + HIR::Lifetime l = lower_lifetime (lifetime); + lifetime_args.push_back (std::move (l)); + } + + std::vector> type_args; + std::vector const_args; + + for (auto &arg : args.get_generic_args ()) + { + switch (arg.get_kind ()) + { + case AST::GenericArg::Kind::Type: { + auto type = ASTLoweringType::translate (arg.get_type ().get ()); + type_args.emplace_back (std::unique_ptr (type)); + break; + } + case AST::GenericArg::Kind::Const: { + auto expr + = ASTLoweringExpr::translate (arg.get_expression ().get ()); + const_args.emplace_back ( + HIR::ConstGenericArg (std::unique_ptr (expr), + expr->get_locus ())); + break; + } + default: + gcc_unreachable (); + } + } + + return HIR::GenericArgs (std::move (lifetime_args), std::move (type_args), + std::move (binding_args), std::move (const_args), + args.get_locus ()); +} + +HIR::SelfParam +ASTLoweringBase::lower_self (AST::SelfParam &self) +{ + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, self.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + if (self.has_type ()) + { + HIR::Type *type = ASTLoweringType::translate (self.get_type ().get ()); + return HIR::SelfParam (mapping, std::unique_ptr (type), + self.get_is_mut (), self.get_locus ()); + } + else if (!self.get_has_ref ()) + { + return HIR::SelfParam (mapping, std::unique_ptr (nullptr), + self.get_is_mut (), self.get_locus ()); + } + + AST::Lifetime l = self.get_lifetime (); + return HIR::SelfParam (mapping, lower_lifetime (l), self.get_is_mut (), + self.get_locus ()); +} + +void +ASTLowerTypePath::visit (AST::TypePathSegmentGeneric &segment) +{ + std::vector binding_args; // TODO + + std::string segment_name = segment.get_ident_segment ().as_string (); + bool has_separating_scope_resolution + = segment.get_separating_scope_resolution (); + + auto generic_args = lower_generic_args (segment.get_generic_args ()); + + auto crate_num = mappings->get_current_crate (); + auto hirid = mappings->get_next_hir_id (crate_num); + Analysis::NodeMapping mapping (crate_num, segment.get_node_id (), hirid, + UNKNOWN_LOCAL_DEFID); + + translated_segment + = new HIR::TypePathSegmentGeneric (std::move (mapping), segment_name, + has_separating_scope_resolution, + generic_args, segment.get_locus ()); +} + +void +ASTLowerQualifiedPathInType::visit (AST::QualifiedPathInType &path) +{ + auto crate_num = mappings->get_current_crate (); + auto hirid = mappings->get_next_hir_id (crate_num); + Analysis::NodeMapping qual_mappings ( + crate_num, path.get_qualified_path_type ().get_node_id (), hirid, + UNKNOWN_LOCAL_DEFID); + + HIR::Type *qual_type = ASTLoweringType::translate ( + path.get_qualified_path_type ().get_type ().get ()); + HIR::TypePath *qual_trait = ASTLowerTypePath::translate ( + path.get_qualified_path_type ().get_as_type_path ()); + + HIR::QualifiedPathType qual_path_type ( + qual_mappings, std::unique_ptr (qual_type), + std::unique_ptr (qual_trait), + path.get_qualified_path_type ().get_locus ()); + + translated_segment = nullptr; + path.get_associated_segment ()->accept_vis (*this); + if (translated_segment == nullptr) + { + rust_fatal_error (path.get_associated_segment ()->get_locus (), + "failed to translate AST TypePathSegment"); + return; + } + std::unique_ptr associated_segment (translated_segment); + + std::vector> translated_segments; + for (auto &seg : path.get_segments ()) + { + translated_segment = nullptr; + seg->accept_vis (*this); + if (translated_segment == nullptr) + { + rust_fatal_error (seg->get_locus (), + "failed to translte AST TypePathSegment"); + } + translated_segments.push_back ( + std::unique_ptr (translated_segment)); + } + + Analysis::NodeMapping mapping (crate_num, path.get_node_id (), hirid, + mappings->get_next_localdef_id (crate_num)); + translated = new HIR::QualifiedPathInType (std::move (mapping), + std::move (qual_path_type), + std::move (associated_segment), + std::move (translated_segments), + path.get_locus ()); +} + +void +ASTLoweringType::visit (AST::TraitObjectTypeOneBound &type) +{ + std::vector> bounds; + HIR::TypeParamBound *translated_bound + = ASTLoweringTypeBounds::translate (&type.get_trait_bound ()); + bounds.push_back (std::unique_ptr (translated_bound)); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, type.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::TraitObjectType (mapping, std::move (bounds), + type.get_locus (), type.is_dyn ()); +} + +void +ASTLoweringType::visit (AST::TraitObjectType &type) +{ + std::vector> bounds; + + for (auto &bound : type.get_type_param_bounds ()) + { + HIR::TypeParamBound *translated_bound + = ASTLoweringTypeBounds::translate (bound.get ()); + bounds.push_back ( + std::unique_ptr (translated_bound)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, type.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::TraitObjectType (mapping, std::move (bounds), + type.get_locus (), type.is_dyn ()); +} + +HIR::Type * +ASTLoweringBase::lower_type_no_bounds (AST::TypeNoBounds *type) +{ + return ASTLoweringType::translate (type); +} + +HIR::TypeParamBound * +ASTLoweringBase::lower_bound (AST::TypeParamBound *bound) +{ + return ASTLoweringTypeBounds::translate (bound); +} + +/* Checks whether the name of a field already exists. Returns true + and produces an error if so. */ +bool +struct_field_name_exists (std::vector &fields, + HIR::StructField &new_field) +{ + for (auto &field : fields) + { + if (field.get_field_name ().compare (new_field.get_field_name ()) == 0) + { + RichLocation r (new_field.get_locus ()); + r.add_range (field.get_locus ()); + rust_error_at (r, "duplicate field name %qs", + field.get_field_name ().c_str ()); + return true; + } + } + return false; +} + +HIR::FunctionQualifiers +ASTLoweringBase::lower_qualifiers (const AST::FunctionQualifiers &qualifiers) +{ + Unsafety unsafety + = qualifiers.is_unsafe () ? Unsafety::Unsafe : Unsafety::Normal; + bool has_extern = qualifiers.is_extern (); + + ABI abi = ABI::RUST; + if (qualifiers.has_abi ()) + { + const std::string &extern_abi = qualifiers.get_extern_abi (); + abi = get_abi_from_string (extern_abi); + if (has_extern && abi == ABI::UNKNOWN) + rust_error_at (qualifiers.get_locus (), "unknown ABI option"); + } + + return HIR::FunctionQualifiers (qualifiers.get_const_status (), unsafety, + has_extern, abi); +} + +void +ASTLoweringBase::handle_outer_attributes (const HIR::Item &item) +{ + for (const auto &attr : item.get_outer_attrs ()) + { + const auto &str_path = attr.get_path ().as_string (); + if (!is_known_attribute (str_path)) + { + rust_error_at (attr.get_locus (), "unknown attribute"); + continue; + } + + bool is_lang_item = str_path.compare ("lang") == 0 + && attr.has_attr_input () + && attr.get_attr_input ().get_attr_input_type () + == AST::AttrInput::AttrInputType::LITERAL; + + bool is_doc_item = str_path.compare ("doc") == 0; + + if (is_doc_item) + handle_doc_item_attribute (item, attr); + else if (is_lang_item) + handle_lang_item_attribute (item, attr); + else if (!attribute_handled_in_another_pass (str_path)) + { + rust_error_at (attr.get_locus (), "unhandled attribute: [%s]", + attr.get_path ().as_string ().c_str ()); + } + } +} + +void +ASTLoweringBase::handle_doc_item_attribute (const HIR::Item &item, + const AST::Attribute &attr) +{ + auto simple_doc_comment = attr.has_attr_input () + && attr.get_attr_input ().get_attr_input_type () + == AST::AttrInput::AttrInputType::LITERAL; + if (simple_doc_comment) + return; + + const AST::AttrInput &input = attr.get_attr_input (); + bool is_token_tree + = input.get_attr_input_type () == AST::AttrInput::AttrInputType::TOKEN_TREE; + rust_assert (is_token_tree); + const auto &option = static_cast (input); + AST::AttrInputMetaItemContainer *meta_item = option.parse_to_meta_item (); + + // TODO: add actual and complete checks for the doc attributes + // + // FIXME: Move this to the AttributeChecker visitor + rust_assert (meta_item); +} + +void +ASTLoweringBase::handle_lang_item_attribute (const HIR::Item &item, + const AST::Attribute &attr) +{ + auto &literal = static_cast (attr.get_attr_input ()); + const auto &lang_item_type_str = literal.get_literal ().as_string (); + auto lang_item_type = Analysis::RustLangItem::Parse (lang_item_type_str); + if (lang_item_type == Analysis::RustLangItem::ItemType::UNKNOWN) + { + rust_error_at (attr.get_locus (), "unknown lang item"); + return; + } + mappings->insert_lang_item (lang_item_type, + item.get_mappings ().get_defid ()); +} + +bool +ASTLoweringBase::is_known_attribute (const std::string &attribute_path) const +{ + const auto &lookup = attr_mappings->lookup_builtin (attribute_path); + return !lookup.is_error (); +} + +bool +ASTLoweringBase::attribute_handled_in_another_pass ( + const std::string &attribute_path) const +{ + const auto &lookup = attr_mappings->lookup_builtin (attribute_path); + if (lookup.is_error ()) + return false; + + if (lookup.handler == Analysis::CompilerPass::UNKNOWN) + return false; + + return lookup.handler != Analysis::CompilerPass::HIR_LOWERING; +} + +std::unique_ptr +ASTLoweringBase::lower_tuple_pattern_multiple ( + AST::TuplePatternItemsMultiple &pattern) +{ + std::vector> patterns; + for (auto &p : pattern.get_patterns ()) + { + HIR::Pattern *translated = ASTLoweringPattern::translate (p.get ()); + patterns.push_back (std::unique_ptr (translated)); + } + + return std::unique_ptr ( + new HIR::TuplePatternItemsMultiple (std::move (patterns))); +} + +std::unique_ptr +ASTLoweringBase::lower_tuple_pattern_ranged ( + AST::TuplePatternItemsRanged &pattern) +{ + std::vector> lower_patterns; + std::vector> upper_patterns; + + for (auto &p : pattern.get_lower_patterns ()) + { + HIR::Pattern *translated = ASTLoweringPattern::translate (p.get ()); + lower_patterns.push_back (std::unique_ptr (translated)); + } + + for (auto &p : pattern.get_upper_patterns ()) + { + HIR::Pattern *translated = ASTLoweringPattern::translate (p.get ()); + upper_patterns.push_back (std::unique_ptr (translated)); + } + + return std::unique_ptr ( + new HIR::TuplePatternItemsRanged (std::move (lower_patterns), + std::move (upper_patterns))); +} + +std::unique_ptr +ASTLoweringBase::lower_range_pattern_bound (AST::RangePatternBound *bound) +{ + std::unique_ptr hir_bound = nullptr; + switch (bound->get_bound_type ()) + { + case AST::RangePatternBound::RangePatternBoundType::LITERAL: { + AST::RangePatternBoundLiteral &ref + = *static_cast (bound); + + HIR::Literal literal = lower_literal (ref.get_literal ()); + + hir_bound = std::unique_ptr ( + new HIR::RangePatternBoundLiteral (literal, ref.get_locus (), + ref.get_has_minus ())); + } + break; + case AST::RangePatternBound::RangePatternBoundType::PATH: { + AST::RangePatternBoundPath &ref + = *static_cast (bound); + + HIR::PathInExpression *path + = ASTLowerPathInExpression::translate (&ref.get_path ()); + + hir_bound = std::unique_ptr ( + new HIR::RangePatternBoundPath (*path)); + } + break; + case AST::RangePatternBound::RangePatternBoundType::QUALPATH: { + AST::RangePatternBoundQualPath &ref + = *static_cast (bound); + + HIR::QualifiedPathInExpression *qualpath + = ASTLowerQualPathInExpression::translate ( + &ref.get_qualified_path ()); + + hir_bound = std::unique_ptr ( + new HIR::RangePatternBoundQualPath (*qualpath)); + } + break; + } + + return hir_bound; +} + +HIR::Literal +ASTLoweringBase::lower_literal (const AST::Literal &literal) +{ + HIR::Literal::LitType type = HIR::Literal::LitType::CHAR; + switch (literal.get_lit_type ()) + { + case AST::Literal::LitType::CHAR: + type = HIR::Literal::LitType::CHAR; + break; + case AST::Literal::LitType::STRING: + type = HIR::Literal::LitType::STRING; + break; + case AST::Literal::LitType::BYTE: + type = HIR::Literal::LitType::BYTE; + break; + case AST::Literal::LitType::BYTE_STRING: + type = HIR::Literal::LitType::BYTE_STRING; + break; + case AST::Literal::LitType::INT: + type = HIR::Literal::LitType::INT; + break; + case AST::Literal::LitType::FLOAT: + type = HIR::Literal::LitType::FLOAT; + break; + case AST::Literal::LitType::BOOL: + type = HIR::Literal::LitType::BOOL; + break; + case AST::Literal::LitType::ERROR: + gcc_unreachable (); + break; + } + + return HIR::Literal (literal.as_string (), type, literal.get_type_hint ()); +} + +HIR::ExternBlock * +ASTLoweringBase::lower_extern_block (AST::ExternBlock &extern_block) +{ + HIR::Visibility vis = translate_visibility (extern_block.get_visibility ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, extern_block.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + std::vector> extern_items; + for (auto &item : extern_block.get_extern_items ()) + { + if (item->is_marked_for_strip ()) + continue; + + HIR::ExternalItem *lowered + = ASTLoweringExternItem::translate (item.get (), mapping.get_hirid ()); + extern_items.push_back (std::unique_ptr (lowered)); + } + + ABI abi = ABI::RUST; + if (extern_block.has_abi ()) + { + const std::string &extern_abi = extern_block.get_abi (); + abi = get_abi_from_string (extern_abi); + if (abi == ABI::UNKNOWN) + rust_error_at (extern_block.get_locus (), "unknown ABI option"); + } + + HIR::ExternBlock *hir_extern_block + = new HIR::ExternBlock (mapping, abi, std::move (extern_items), + std::move (vis), extern_block.get_inner_attrs (), + extern_block.get_outer_attrs (), + extern_block.get_locus ()); + + mappings->insert_hir_extern_block (hir_extern_block); + + return hir_extern_block; +} + +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h new file mode 100644 index 00000000000..68c57e0c02b --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower-base.h @@ -0,0 +1,297 @@ +// 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_LOWER_BASE +#define RUST_AST_LOWER_BASE + +#include "rust-system.h" +#include "rust-ast-full.h" +#include "rust-ast-visitor.h" +#include "rust-hir-map.h" +#include "rust-hir-full.h" +#include "rust-attributes.h" + +namespace Rust { +namespace HIR { + +// base class to allow derivatives to overload as needed +class ASTLoweringBase : public AST::ASTVisitor +{ +public: + virtual ~ASTLoweringBase () {} + + // visitor impl + // rust-ast.h + // virtual void visit(AttrInput& attr_input); + // virtual void visit(TokenTree& token_tree); + // virtual void visit(MacroMatch& macro_match); + virtual void visit (AST::Token &tok); + virtual void visit (AST::DelimTokenTree &delim_tok_tree); + virtual void visit (AST::AttrInputMetaItemContainer &input); + // virtual void visit(MetaItem& meta_item); + // void vsit(Stmt& stmt); + // virtual void visit(Expr& expr); + virtual void visit (AST::IdentifierExpr &ident_expr); + // virtual void visit(Pattern& pattern); + // virtual void visit(Type& type); + // virtual void visit(TypeParamBound& type_param_bound); + virtual void visit (AST::Lifetime &lifetime); + // virtual void visit(GenericParam& generic_param); + virtual void visit (AST::LifetimeParam &lifetime_param); + virtual void visit (AST::ConstGenericParam &const_param); + // virtual void visit(TraitItem& trait_item); + // virtual void visit(InherentImplItem& inherent_impl_item); + // virtual void visit(TraitImplItem& trait_impl_item); + + // rust-path.h + virtual void visit (AST::PathInExpression &path); + virtual void visit (AST::TypePathSegment &segment); + virtual void visit (AST::TypePathSegmentGeneric &segment); + virtual void visit (AST::TypePathSegmentFunction &segment); + virtual void visit (AST::TypePath &path); + virtual void visit (AST::QualifiedPathInExpression &path); + virtual void visit (AST::QualifiedPathInType &path); + + // rust-expr.h + virtual void visit (AST::LiteralExpr &expr); + virtual void visit (AST::AttrInputLiteral &attr_input); + virtual void visit (AST::MetaItemLitExpr &meta_item); + virtual void visit (AST::MetaItemPathLit &meta_item); + virtual void visit (AST::BorrowExpr &expr); + virtual void visit (AST::DereferenceExpr &expr); + virtual void visit (AST::ErrorPropagationExpr &expr); + virtual void visit (AST::NegationExpr &expr); + virtual void visit (AST::ArithmeticOrLogicalExpr &expr); + virtual void visit (AST::ComparisonExpr &expr); + virtual void visit (AST::LazyBooleanExpr &expr); + virtual void visit (AST::TypeCastExpr &expr); + virtual void visit (AST::AssignmentExpr &expr); + virtual void visit (AST::CompoundAssignmentExpr &expr); + virtual void visit (AST::GroupedExpr &expr); + // virtual void visit(ArrayElems& elems); + virtual void visit (AST::ArrayElemsValues &elems); + virtual void visit (AST::ArrayElemsCopied &elems); + virtual void visit (AST::ArrayExpr &expr); + virtual void visit (AST::ArrayIndexExpr &expr); + virtual void visit (AST::TupleExpr &expr); + virtual void visit (AST::TupleIndexExpr &expr); + virtual void visit (AST::StructExprStruct &expr); + // virtual void visit(StructExprField& field); + virtual void visit (AST::StructExprFieldIdentifier &field); + virtual void visit (AST::StructExprFieldIdentifierValue &field); + virtual void visit (AST::StructExprFieldIndexValue &field); + virtual void visit (AST::StructExprStructFields &expr); + virtual void visit (AST::StructExprStructBase &expr); + virtual void visit (AST::CallExpr &expr); + virtual void visit (AST::MethodCallExpr &expr); + virtual void visit (AST::FieldAccessExpr &expr); + virtual void visit (AST::ClosureExprInner &expr); + virtual void visit (AST::BlockExpr &expr); + virtual void visit (AST::ClosureExprInnerTyped &expr); + virtual void visit (AST::ContinueExpr &expr); + virtual void visit (AST::BreakExpr &expr); + virtual void visit (AST::RangeFromToExpr &expr); + virtual void visit (AST::RangeFromExpr &expr); + virtual void visit (AST::RangeToExpr &expr); + virtual void visit (AST::RangeFullExpr &expr); + virtual void visit (AST::RangeFromToInclExpr &expr); + virtual void visit (AST::RangeToInclExpr &expr); + virtual void visit (AST::ReturnExpr &expr); + virtual void visit (AST::UnsafeBlockExpr &expr); + virtual void visit (AST::LoopExpr &expr); + virtual void visit (AST::WhileLoopExpr &expr); + virtual void visit (AST::WhileLetLoopExpr &expr); + virtual void visit (AST::ForLoopExpr &expr); + virtual void visit (AST::IfExpr &expr); + virtual void visit (AST::IfExprConseqElse &expr); + virtual void visit (AST::IfExprConseqIf &expr); + virtual void visit (AST::IfExprConseqIfLet &expr); + virtual void visit (AST::IfLetExpr &expr); + virtual void visit (AST::IfLetExprConseqElse &expr); + virtual void visit (AST::IfLetExprConseqIf &expr); + virtual void visit (AST::IfLetExprConseqIfLet &expr); + // virtual void visit(MatchCase& match_case); + // virtual void visit (AST::MatchCaseBlockExpr &match_case); + // virtual void visit (AST::MatchCaseExpr &match_case); + virtual void visit (AST::MatchExpr &expr); + virtual void visit (AST::AwaitExpr &expr); + virtual void visit (AST::AsyncBlockExpr &expr); + + // rust-item.h + virtual void visit (AST::TypeParam ¶m); + // virtual void visit(WhereClauseItem& item); + virtual void visit (AST::LifetimeWhereClauseItem &item); + virtual void visit (AST::TypeBoundWhereClauseItem &item); + virtual void visit (AST::Method &method); + virtual void visit (AST::Module &module); + virtual void visit (AST::ExternCrate &crate); + // virtual void visit(UseTree& use_tree); + virtual void visit (AST::UseTreeGlob &use_tree); + virtual void visit (AST::UseTreeList &use_tree); + virtual void visit (AST::UseTreeRebind &use_tree); + virtual void visit (AST::UseDeclaration &use_decl); + virtual void visit (AST::Function &function); + virtual void visit (AST::TypeAlias &type_alias); + virtual void visit (AST::StructStruct &struct_item); + virtual void visit (AST::TupleStruct &tuple_struct); + virtual void visit (AST::EnumItem &item); + virtual void visit (AST::EnumItemTuple &item); + virtual void visit (AST::EnumItemStruct &item); + virtual void visit (AST::EnumItemDiscriminant &item); + virtual void visit (AST::Enum &enum_item); + virtual void visit (AST::Union &union_item); + virtual void visit (AST::ConstantItem &const_item); + virtual void visit (AST::StaticItem &static_item); + virtual void visit (AST::TraitItemFunc &item); + virtual void visit (AST::TraitItemMethod &item); + virtual void visit (AST::TraitItemConst &item); + virtual void visit (AST::TraitItemType &item); + virtual void visit (AST::Trait &trait); + virtual void visit (AST::InherentImpl &impl); + virtual void visit (AST::TraitImpl &impl); + // virtual void visit(ExternalItem& item); + virtual void visit (AST::ExternalStaticItem &item); + virtual void visit (AST::ExternalFunctionItem &item); + virtual void visit (AST::ExternBlock &block); + + // rust-macro.h + virtual void visit (AST::MacroMatchFragment &match); + virtual void visit (AST::MacroMatchRepetition &match); + virtual void visit (AST::MacroMatcher &matcher); + virtual void visit (AST::MacroRulesDefinition &rules_def); + virtual void visit (AST::MacroInvocation ¯o_invoc); + virtual void visit (AST::MetaItemPath &meta_item); + virtual void visit (AST::MetaItemSeq &meta_item); + virtual void visit (AST::MetaWord &meta_item); + virtual void visit (AST::MetaNameValueStr &meta_item); + virtual void visit (AST::MetaListPaths &meta_item); + virtual void visit (AST::MetaListNameValueStr &meta_item); + + // rust-pattern.h + virtual void visit (AST::LiteralPattern &pattern); + virtual void visit (AST::IdentifierPattern &pattern); + virtual void visit (AST::WildcardPattern &pattern); + // virtual void visit(RangePatternBound& bound); + virtual void visit (AST::RangePatternBoundLiteral &bound); + virtual void visit (AST::RangePatternBoundPath &bound); + virtual void visit (AST::RangePatternBoundQualPath &bound); + virtual void visit (AST::RangePattern &pattern); + virtual void visit (AST::ReferencePattern &pattern); + // virtual void visit(StructPatternField& field); + virtual void visit (AST::StructPatternFieldTuplePat &field); + virtual void visit (AST::StructPatternFieldIdentPat &field); + virtual void visit (AST::StructPatternFieldIdent &field); + virtual void visit (AST::StructPattern &pattern); + // virtual void visit(TupleStructItems& tuple_items); + virtual void visit (AST::TupleStructItemsNoRange &tuple_items); + virtual void visit (AST::TupleStructItemsRange &tuple_items); + virtual void visit (AST::TupleStructPattern &pattern); + // virtual void visit(TuplePatternItems& tuple_items); + virtual void visit (AST::TuplePatternItemsMultiple &tuple_items); + virtual void visit (AST::TuplePatternItemsRanged &tuple_items); + virtual void visit (AST::TuplePattern &pattern); + virtual void visit (AST::GroupedPattern &pattern); + virtual void visit (AST::SlicePattern &pattern); + + // rust-stmt.h + virtual void visit (AST::EmptyStmt &stmt); + virtual void visit (AST::LetStmt &stmt); + virtual void visit (AST::ExprStmtWithoutBlock &stmt); + virtual void visit (AST::ExprStmtWithBlock &stmt); + + // rust-type.h + virtual void visit (AST::TraitBound &bound); + virtual void visit (AST::ImplTraitType &type); + virtual void visit (AST::TraitObjectType &type); + virtual void visit (AST::ParenthesisedType &type); + virtual void visit (AST::ImplTraitTypeOneBound &type); + virtual void visit (AST::TraitObjectTypeOneBound &type); + virtual void visit (AST::TupleType &type); + virtual void visit (AST::NeverType &type); + virtual void visit (AST::RawPointerType &type); + virtual void visit (AST::ReferenceType &type); + virtual void visit (AST::ArrayType &type); + virtual void visit (AST::SliceType &type); + virtual void visit (AST::InferredType &type); + virtual void visit (AST::BareFunctionType &type); + +protected: + ASTLoweringBase () + : mappings (Analysis::Mappings::get ()), + attr_mappings (Analysis::BuiltinAttributeMappings::get ()) + {} + + Analysis::Mappings *mappings; + Analysis::BuiltinAttributeMappings *attr_mappings; + + HIR::Lifetime lower_lifetime (AST::Lifetime &lifetime); + + HIR::LoopLabel lower_loop_label (AST::LoopLabel &loop_label); + + std::vector > lower_generic_params ( + std::vector > ¶ms); + + HIR::PathExprSegment lower_path_expr_seg (AST::PathExprSegment &s); + + HIR::GenericArgs lower_generic_args (AST::GenericArgs &args); + + HIR::GenericArgsBinding lower_binding (AST::GenericArgsBinding &binding); + + HIR::SelfParam lower_self (AST::SelfParam &self); + + HIR::Type *lower_type_no_bounds (AST::TypeNoBounds *type); + + HIR::TypeParamBound *lower_bound (AST::TypeParamBound *bound); + + HIR::QualifiedPathType + lower_qual_path_type (AST::QualifiedPathType &qual_path_type); + + HIR::FunctionQualifiers + lower_qualifiers (const AST::FunctionQualifiers &qualifiers); + + void handle_outer_attributes (const HIR::Item &item); + + void handle_lang_item_attribute (const HIR::Item &item, + const AST::Attribute &attr); + + void handle_doc_item_attribute (const HIR::Item &item, + const AST::Attribute &attr); + + bool is_known_attribute (const std::string &attribute_path) const; + + bool + attribute_handled_in_another_pass (const std::string &attribute_path) const; + + std::unique_ptr + lower_tuple_pattern_multiple (AST::TuplePatternItemsMultiple &pattern); + + std::unique_ptr + lower_tuple_pattern_ranged (AST::TuplePatternItemsRanged &pattern); + + std::unique_ptr + lower_range_pattern_bound (AST::RangePatternBound *bound); + + HIR::Literal lower_literal (const AST::Literal &literal); + + HIR::ExternBlock *lower_extern_block (AST::ExternBlock &extern_block); +}; + +} // namespace HIR +} // namespace Rust + +#endif // RUST_AST_LOWER_BASE diff --git a/gcc/rust/hir/rust-ast-lower-block.h b/gcc/rust/hir/rust-ast-lower-block.h new file mode 100644 index 00000000000..0d3c704c6f1 --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower-block.h @@ -0,0 +1,230 @@ +// 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_LOWER_BLOCK +#define RUST_AST_LOWER_BLOCK + +#include "rust-diagnostics.h" +#include "rust-ast-lower-base.h" + +namespace Rust { +namespace HIR { + +class ASTLoweringBlock : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::BlockExpr *translate (AST::BlockExpr *expr, bool *terminated) + { + ASTLoweringBlock resolver; + expr->accept_vis (resolver); + if (resolver.translated != nullptr) + { + resolver.mappings->insert_hir_expr (resolver.translated); + } + + *terminated = resolver.terminated; + return resolver.translated; + } + + static HIR::UnsafeBlockExpr *translate (AST::UnsafeBlockExpr *expr, + bool *terminated) + { + ASTLoweringBlock resolver; + + HIR::BlockExpr *block + = ASTLoweringBlock::translate (expr->get_block_expr ().get (), + terminated); + auto crate_num = resolver.mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr->get_node_id (), + resolver.mappings->get_next_hir_id ( + crate_num), + UNKNOWN_LOCAL_DEFID); + + HIR::UnsafeBlockExpr *translated + = new HIR::UnsafeBlockExpr (mapping, + std::unique_ptr (block), + expr->get_outer_attrs (), expr->get_locus ()); + + resolver.mappings->insert_hir_expr (translated); + + return translated; + } + + void visit (AST::BlockExpr &expr) override; + +private: + ASTLoweringBlock () + : ASTLoweringBase (), translated (nullptr), terminated (false) + {} + + HIR::BlockExpr *translated; + bool terminated; +}; + +class ASTLoweringIfBlock : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::IfExpr *translate (AST::IfExpr *expr, bool *terminated) + { + ASTLoweringIfBlock resolver; + expr->accept_vis (resolver); + if (resolver.translated != nullptr) + { + resolver.mappings->insert_hir_expr (resolver.translated); + } + *terminated = resolver.terminated; + return resolver.translated; + } + + ~ASTLoweringIfBlock () {} + + void visit (AST::IfExpr &expr) override; + + void visit (AST::IfExprConseqElse &expr) override; + + void visit (AST::IfExprConseqIf &expr) override; + +private: + ASTLoweringIfBlock () + : ASTLoweringBase (), translated (nullptr), terminated (false) + {} + + HIR::IfExpr *translated; + bool terminated; +}; + +class ASTLoweringIfLetBlock : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::IfLetExpr *translate (AST::IfLetExpr *expr) + { + ASTLoweringIfLetBlock resolver; + expr->accept_vis (resolver); + if (resolver.translated != nullptr) + { + resolver.mappings->insert_hir_expr (resolver.translated); + } + return resolver.translated; + } + + ~ASTLoweringIfLetBlock () {} + + void visit (AST::IfLetExpr &expr) override; + +private: + ASTLoweringIfLetBlock () : ASTLoweringBase (), translated (nullptr) {} + + HIR::IfLetExpr *translated; +}; + +class ASTLoweringExprWithBlock : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::ExprWithBlock *translate (AST::ExprWithBlock *expr, + bool *terminated) + { + ASTLoweringExprWithBlock resolver; + expr->accept_vis (resolver); + if (resolver.translated != nullptr) + { + resolver.mappings->insert_hir_expr (resolver.translated); + } + + *terminated = resolver.terminated; + return resolver.translated; + } + + ~ASTLoweringExprWithBlock () {} + + void visit (AST::IfExpr &expr) override + { + translated = ASTLoweringIfBlock::translate (&expr, &terminated); + } + + void visit (AST::IfExprConseqElse &expr) override + { + translated = ASTLoweringIfBlock::translate (&expr, &terminated); + } + + void visit (AST::IfExprConseqIf &expr) override + { + translated = ASTLoweringIfBlock::translate (&expr, &terminated); + } + + void visit (AST::IfLetExpr &expr) override + { + translated = ASTLoweringIfLetBlock::translate (&expr); + } + + void visit (AST::BlockExpr &expr) override + { + translated = ASTLoweringBlock::translate (&expr, &terminated); + } + + void visit (AST::UnsafeBlockExpr &expr) override + { + translated = ASTLoweringBlock::translate (&expr, &terminated); + } + + void visit (AST::LoopExpr &expr) override + { + HIR::BlockExpr *loop_block + = ASTLoweringBlock::translate (expr.get_loop_block ().get (), + &terminated); + + HIR::LoopLabel loop_label = lower_loop_label (expr.get_loop_label ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::LoopExpr (mapping, + std::unique_ptr (loop_block), + expr.get_locus (), std::move (loop_label), + expr.get_outer_attrs ()); + } + + void visit (AST::WhileLoopExpr &expr) override; + + void visit (AST::ForLoopExpr &expr) override; + + void visit (AST::MatchExpr &expr) override; + +private: + ASTLoweringExprWithBlock () + : ASTLoweringBase (), translated (nullptr), terminated (false) + {} + + HIR::ExprWithBlock *translated; + bool terminated; +}; + +} // namespace HIR +} // namespace Rust + +#endif // RUST_AST_LOWER_BLOCK diff --git a/gcc/rust/hir/rust-ast-lower-enumitem.h b/gcc/rust/hir/rust-ast-lower-enumitem.h new file mode 100644 index 00000000000..b76658c78cc --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower-enumitem.h @@ -0,0 +1,181 @@ +// 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_LOWER_ENUMITEM +#define RUST_AST_LOWER_ENUMITEM + +#include "rust-ast-lower.h" +#include "rust-diagnostics.h" + +#include "rust-ast-lower-base.h" +#include "rust-ast-lower-type.h" +#include "rust-ast-lower-expr.h" +#include "rust-hir-full-decls.h" + +namespace Rust { +namespace HIR { + +class ASTLoweringEnumItem : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::EnumItem *translate (AST::EnumItem *item) + { + ASTLoweringEnumItem resolver; + item->accept_vis (resolver); + + rust_assert (resolver.translated != nullptr); + + auto hirid = resolver.translated->get_mappings ().get_hirid (); + auto defid = resolver.translated->get_mappings ().get_defid (); + + resolver.mappings->insert_defid_mapping (defid, resolver.translated); + resolver.mappings->insert_hir_item (resolver.translated); + resolver.mappings->insert_location (hirid, + resolver.translated->get_locus ()); + + return resolver.translated; + } + + void visit (AST::EnumItem &item) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, item.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + if (item.has_visibility ()) + rust_error_at (item.get_locus (), + "visibility qualifier %qs not allowed on enum item", + item.get_visibility ().as_string ().c_str ()); + translated = new HIR::EnumItem (mapping, item.get_identifier (), + item.get_outer_attrs (), item.get_locus ()); + } + + void visit (AST::EnumItemTuple &item) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, item.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + if (item.has_visibility ()) + rust_error_at (item.get_locus (), + "visibility qualifier %qs not allowed on enum item", + item.get_visibility ().as_string ().c_str ()); + + std::vector fields; + for (auto &field : item.get_tuple_fields ()) + { + HIR::Visibility vis = translate_visibility (field.get_visibility ()); + HIR::Type *type + = ASTLoweringType::translate (field.get_field_type ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping field_mapping ( + crate_num, field.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + HIR::TupleField translated_field (field_mapping, + std::unique_ptr (type), + vis, field.get_locus (), + field.get_outer_attrs ()); + fields.push_back (std::move (translated_field)); + } + + translated + = new HIR::EnumItemTuple (mapping, item.get_identifier (), + std::move (fields), item.get_outer_attrs (), + item.get_locus ()); + } + + void visit (AST::EnumItemStruct &item) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, item.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + if (item.has_visibility ()) + rust_error_at (item.get_locus (), + "visibility qualifier %qs not allowed on enum item", + item.get_visibility ().as_string ().c_str ()); + + std::vector fields; + for (auto &field : item.get_struct_fields ()) + { + HIR::Visibility vis = translate_visibility (field.get_visibility ()); + HIR::Type *type + = ASTLoweringType::translate (field.get_field_type ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping field_mapping ( + crate_num, field.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + HIR::StructField translated_field (field_mapping, + field.get_field_name (), + std::unique_ptr (type), + vis, field.get_locus (), + field.get_outer_attrs ()); + + if (struct_field_name_exists (fields, translated_field)) + break; + + fields.push_back (std::move (translated_field)); + } + + translated + = new HIR::EnumItemStruct (mapping, item.get_identifier (), + std::move (fields), item.get_outer_attrs (), + item.get_locus ()); + } + + void visit (AST::EnumItemDiscriminant &item) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, item.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + if (item.has_visibility ()) + rust_error_at (item.get_locus (), + "visibility qualifier %qs not allowed on enum item", + item.get_visibility ().as_string ().c_str ()); + + HIR::Expr *expr = ASTLoweringExpr::translate (item.get_expr ().get ()); + translated + = new HIR::EnumItemDiscriminant (mapping, item.get_identifier (), + std::unique_ptr (expr), + item.get_outer_attrs (), + item.get_locus ()); + } + +private: + ASTLoweringEnumItem () : translated (nullptr) {} + + HIR::EnumItem *translated; +}; + +} // namespace HIR +} // namespace Rust + +#endif // RUST_AST_LOWER_ENUMITEM diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h new file mode 100644 index 00000000000..4f7f40f27e4 --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower-expr.h @@ -0,0 +1,766 @@ +// 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_LOWER_EXPR +#define RUST_AST_LOWER_EXPR + +#include "rust-diagnostics.h" +#include "rust-ast-lower-base.h" +#include "rust-ast-lower-block.h" +#include "rust-ast-lower-struct-field-expr.h" +#include "rust-ast-lower-pattern.h" + +namespace Rust { +namespace HIR { + +class ASTLowerPathInExpression : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::PathInExpression *translate (AST::PathInExpression *expr) + { + ASTLowerPathInExpression compiler; + expr->accept_vis (compiler); + rust_assert (compiler.translated); + return compiler.translated; + } + + void visit (AST::PathInExpression &expr) override; + +private: + ASTLowerPathInExpression () : translated (nullptr) {} + + HIR::PathInExpression *translated; +}; + +class ASTLowerQualPathInExpression : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::QualifiedPathInExpression * + translate (AST::QualifiedPathInExpression *expr) + { + ASTLowerQualPathInExpression compiler; + expr->accept_vis (compiler); + rust_assert (compiler.translated); + return compiler.translated; + } + + void visit (AST::QualifiedPathInExpression &expr) override; + +private: + ASTLowerQualPathInExpression () : translated (nullptr) {} + + HIR::QualifiedPathInExpression *translated; +}; + +class ASTLoweringExpr : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::Expr *translate (AST::Expr *expr, bool *terminated = nullptr) + { + ASTLoweringExpr resolver; + expr->accept_vis (resolver); + if (resolver.translated == nullptr) + { + rust_fatal_error (expr->get_locus (), "Failed to lower expr: [%s]", + expr->as_string ().c_str ()); + return nullptr; + } + + resolver.mappings->insert_hir_expr (resolver.translated); + resolver.mappings->insert_location ( + resolver.translated->get_mappings ().get_hirid (), expr->get_locus ()); + + if (terminated != nullptr) + *terminated = resolver.terminated; + + return resolver.translated; + } + + void visit (AST::TupleIndexExpr &expr) override + { + HIR::Expr *tuple_expr + = ASTLoweringExpr::translate (expr.get_tuple_expr ().get (), &terminated); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::TupleIndexExpr (mapping, + std::unique_ptr (tuple_expr), + expr.get_tuple_index (), + expr.get_outer_attrs (), expr.get_locus ()); + } + + void visit (AST::TupleExpr &expr) override + { + std::vector > tuple_elements; + for (auto &e : expr.get_tuple_elems ()) + { + HIR::Expr *t = ASTLoweringExpr::translate (e.get ()); + tuple_elements.push_back (std::unique_ptr (t)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::TupleExpr (std::move (mapping), std::move (tuple_elements), + expr.get_inner_attrs (), expr.get_outer_attrs (), + expr.get_locus ()); + } + + void visit (AST::IfExpr &expr) override + { + translated = ASTLoweringIfBlock::translate (&expr, &terminated); + } + + void visit (AST::IfExprConseqElse &expr) override + { + translated = ASTLoweringIfBlock::translate (&expr, &terminated); + } + + void visit (AST::IfExprConseqIf &expr) override + { + translated = ASTLoweringIfBlock::translate (&expr, &terminated); + } + + void visit (AST::BlockExpr &expr) override + { + translated = ASTLoweringBlock::translate (&expr, &terminated); + } + + void visit (AST::UnsafeBlockExpr &expr) override + { + translated = ASTLoweringBlock::translate (&expr, &terminated); + } + + void visit (AST::PathInExpression &expr) override + { + translated = ASTLowerPathInExpression::translate (&expr); + } + + void visit (AST::QualifiedPathInExpression &expr) override + { + translated = ASTLowerQualPathInExpression::translate (&expr); + } + + void visit (AST::ReturnExpr &expr) override + { + terminated = true; + HIR::Expr *return_expr + = expr.has_returned_expr () + ? ASTLoweringExpr::translate (expr.get_returned_expr ().get ()) + : nullptr; + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::ReturnExpr (mapping, expr.get_locus (), + std::unique_ptr (return_expr)); + } + + void visit (AST::CallExpr &expr) override + { + HIR::Expr *func + = ASTLoweringExpr::translate (expr.get_function_expr ().get ()); + + auto const &in_params = expr.get_params (); + std::vector > params; + for (auto ¶m : in_params) + { + auto trans = ASTLoweringExpr::translate (param.get ()); + params.push_back (std::unique_ptr (trans)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping ( + crate_num, UNKNOWN_NODEID /* this can map back to the AST*/, + mappings->get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID); + + translated = new HIR::CallExpr (mapping, std::unique_ptr (func), + std::move (params), expr.get_outer_attrs (), + expr.get_locus ()); + } + + void visit (AST::MethodCallExpr &expr) override + { + HIR::PathExprSegment method_path + = lower_path_expr_seg (expr.get_method_name ()); + + HIR::Expr *receiver + = ASTLoweringExpr::translate (expr.get_receiver_expr ().get ()); + + auto const &in_params = expr.get_params (); + std::vector > params; + for (auto ¶m : in_params) + { + auto trans = ASTLoweringExpr::translate (param.get ()); + params.push_back (std::unique_ptr (trans)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::MethodCallExpr (mapping, std::unique_ptr (receiver), + method_path, std::move (params), + expr.get_outer_attrs (), expr.get_locus ()); + } + + void visit (AST::AssignmentExpr &expr) override + { + HIR::Expr *lhs = ASTLoweringExpr::translate (expr.get_left_expr ().get ()); + HIR::Expr *rhs = ASTLoweringExpr::translate (expr.get_right_expr ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::AssignmentExpr (mapping, std::unique_ptr (lhs), + std::unique_ptr (rhs), + expr.get_locus ()); + } + + void visit (AST::IdentifierExpr &expr) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping1 (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + Analysis::NodeMapping mapping2 (mapping1); + + HIR::PathIdentSegment ident_seg (expr.get_ident ()); + HIR::PathExprSegment seg (mapping1, ident_seg, expr.get_locus (), + HIR::GenericArgs::create_empty ()); + translated = new HIR::PathInExpression (mapping2, {seg}, expr.get_locus (), + false, expr.get_outer_attrs ()); + } + + void visit (AST::ArrayExpr &expr) override + { + expr.get_array_elems ()->accept_vis (*this); + rust_assert (translated_array_elems != nullptr); + HIR::ArrayElems *elems = translated_array_elems; + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::ArrayExpr (mapping, std::unique_ptr (elems), + expr.get_inner_attrs (), expr.get_outer_attrs (), + expr.get_locus ()); + } + + void visit (AST::ArrayIndexExpr &expr) override + { + HIR::Expr *array_expr + = ASTLoweringExpr::translate (expr.get_array_expr ().get ()); + HIR::Expr *array_index_expr + = ASTLoweringExpr::translate (expr.get_index_expr ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::ArrayIndexExpr (mapping, + std::unique_ptr (array_expr), + std::unique_ptr (array_index_expr), + expr.get_outer_attrs (), expr.get_locus ()); + } + + void visit (AST::ArrayElemsValues &elems) override + { + std::vector > elements; + for (auto &elem : elems.get_values ()) + { + HIR::Expr *translated_elem = ASTLoweringExpr::translate (elem.get ()); + elements.push_back (std::unique_ptr (translated_elem)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (mappings->get_current_crate (), + elems.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated_array_elems + = new HIR::ArrayElemsValues (mapping, std::move (elements)); + } + + void visit (AST::ArrayElemsCopied &elems) override + { + HIR::Expr *element + = ASTLoweringExpr::translate (elems.get_elem_to_copy ().get ()); + HIR::Expr *num_copies + = ASTLoweringExpr::translate (elems.get_num_copies ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (mappings->get_current_crate (), + elems.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated_array_elems + = new HIR::ArrayElemsCopied (mapping, + std::unique_ptr (element), + std::unique_ptr (num_copies)); + } + + void visit (AST::LiteralExpr &expr) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + HIR::Literal l = lower_literal (expr.get_literal ()); + translated + = new HIR::LiteralExpr (mapping, std::move (l), expr.get_locus (), + expr.get_outer_attrs ()); + } + + void visit (AST::ArithmeticOrLogicalExpr &expr) override + { + HIR::Expr *lhs = ASTLoweringExpr::translate (expr.get_left_expr ().get ()); + rust_assert (lhs != nullptr); + HIR::Expr *rhs = ASTLoweringExpr::translate (expr.get_right_expr ().get ()); + rust_assert (rhs != nullptr); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::ArithmeticOrLogicalExpr (mapping, + std::unique_ptr (lhs), + std::unique_ptr (rhs), + expr.get_expr_type (), + expr.get_locus ()); + } + + void visit (AST::ComparisonExpr &expr) override + { + HIR::Expr *lhs = ASTLoweringExpr::translate (expr.get_left_expr ().get ()); + rust_assert (lhs != nullptr); + HIR::Expr *rhs = ASTLoweringExpr::translate (expr.get_right_expr ().get ()); + rust_assert (rhs != nullptr); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::ComparisonExpr (mapping, std::unique_ptr (lhs), + std::unique_ptr (rhs), + expr.get_expr_type (), expr.get_locus ()); + } + + void visit (AST::LazyBooleanExpr &expr) override + { + HIR::Expr *lhs = ASTLoweringExpr::translate (expr.get_left_expr ().get ()); + rust_assert (lhs != nullptr); + HIR::Expr *rhs = ASTLoweringExpr::translate (expr.get_right_expr ().get ()); + rust_assert (rhs != nullptr); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::LazyBooleanExpr (mapping, std::unique_ptr (lhs), + std::unique_ptr (rhs), + expr.get_expr_type (), expr.get_locus ()); + } + + void visit (AST::NegationExpr &expr) override + { + HIR::Expr *negated_value + = ASTLoweringExpr::translate (expr.get_negated_expr ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + translated + = new HIR::NegationExpr (mapping, + std::unique_ptr (negated_value), + expr.get_expr_type (), expr.get_outer_attrs (), + expr.get_locus ()); + } + + void visit (AST::TypeCastExpr &expr) override + { + HIR::Expr *expr_to_cast_to + = ASTLoweringExpr::translate (expr.get_casted_expr ().get ()); + HIR::Type *type_to_cast_to + = lower_type_no_bounds (expr.get_type_to_cast_to ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::TypeCastExpr (mapping, + std::unique_ptr (expr_to_cast_to), + std::unique_ptr (type_to_cast_to), + expr.get_locus ()); + } + + void visit (AST::CompoundAssignmentExpr &expr) override + { + ArithmeticOrLogicalOperator op; + switch (expr.get_expr_type ()) + { + case CompoundAssignmentOperator::ADD: + op = ArithmeticOrLogicalOperator::ADD; + break; + case CompoundAssignmentOperator::SUBTRACT: + op = ArithmeticOrLogicalOperator::SUBTRACT; + break; + case CompoundAssignmentOperator::MULTIPLY: + op = ArithmeticOrLogicalOperator::MULTIPLY; + break; + case CompoundAssignmentOperator::DIVIDE: + op = ArithmeticOrLogicalOperator::DIVIDE; + break; + case CompoundAssignmentOperator::MODULUS: + op = ArithmeticOrLogicalOperator::MODULUS; + break; + case CompoundAssignmentOperator::BITWISE_AND: + op = ArithmeticOrLogicalOperator::BITWISE_AND; + break; + case CompoundAssignmentOperator::BITWISE_OR: + op = ArithmeticOrLogicalOperator::BITWISE_OR; + break; + case CompoundAssignmentOperator::BITWISE_XOR: + op = ArithmeticOrLogicalOperator::BITWISE_XOR; + break; + case CompoundAssignmentOperator::LEFT_SHIFT: + op = ArithmeticOrLogicalOperator::LEFT_SHIFT; + break; + case CompoundAssignmentOperator::RIGHT_SHIFT: + op = ArithmeticOrLogicalOperator::RIGHT_SHIFT; + break; + default: + gcc_unreachable (); + } + + HIR::Expr *asignee_expr + = ASTLoweringExpr::translate (expr.get_left_expr ().get ()); + HIR::Expr *value + = ASTLoweringExpr::translate (expr.get_right_expr ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::CompoundAssignmentExpr ( + mapping, std::unique_ptr (asignee_expr), + std::unique_ptr (value), op, expr.get_locus ()); + } + + void visit (AST::StructExprStruct &struct_expr) override + { + HIR::PathInExpression *path + = ASTLowerPathInExpression::translate (&struct_expr.get_struct_name ()); + HIR::PathInExpression copied_path (*path); + delete path; + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, struct_expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::StructExprStruct (mapping, copied_path, + struct_expr.get_inner_attrs (), + struct_expr.get_outer_attrs (), + struct_expr.get_locus ()); + } + + void visit (AST::StructExprStructFields &struct_expr) override + { + // bit of a hack for now + HIR::PathInExpression *path + = ASTLowerPathInExpression::translate (&struct_expr.get_struct_name ()); + HIR::PathInExpression copied_path (*path); + delete path; + + HIR::StructBase *base = nullptr; + if (struct_expr.has_struct_base ()) + { + HIR::Expr *translated_base = ASTLoweringExpr::translate ( + struct_expr.get_struct_base ().get_base_struct ().get ()); + base + = new HIR::StructBase (std::unique_ptr (translated_base)); + } + + auto const &in_fields = struct_expr.get_fields (); + std::vector > fields; + for (auto &field : in_fields) + { + HIR::StructExprField *translated + = ASTLowerStructExprField::translate (field.get ()); + fields.push_back (std::unique_ptr (translated)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, struct_expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::StructExprStructFields ( + mapping, copied_path, std::move (fields), struct_expr.get_locus (), base, + struct_expr.get_inner_attrs (), struct_expr.get_outer_attrs ()); + } + + void visit (AST::GroupedExpr &expr) override + { + HIR::Expr *paren_expr + = ASTLoweringExpr::translate (expr.get_expr_in_parens ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::GroupedExpr (mapping, std::unique_ptr (paren_expr), + expr.get_inner_attrs (), expr.get_outer_attrs (), + expr.get_locus ()); + } + + void visit (AST::FieldAccessExpr &expr) override + { + HIR::Expr *receiver + = ASTLoweringExpr::translate (expr.get_receiver_expr ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + translated + = new HIR::FieldAccessExpr (mapping, + std::unique_ptr (receiver), + expr.get_field_name (), + expr.get_outer_attrs (), expr.get_locus ()); + } + + void visit (AST::LoopExpr &expr) override + { + translated = ASTLoweringExprWithBlock::translate (&expr, &terminated); + } + + void visit (AST::WhileLoopExpr &expr) override + { + translated = ASTLoweringExprWithBlock::translate (&expr, &terminated); + } + + void visit (AST::ForLoopExpr &expr) override + { + translated = ASTLoweringExprWithBlock::translate (&expr, &terminated); + } + + void visit (AST::BreakExpr &expr) override + { + HIR::Lifetime break_label = lower_lifetime (expr.get_label ()); + HIR::Expr *break_expr + = expr.has_break_expr () + ? ASTLoweringExpr::translate (expr.get_break_expr ().get ()) + : nullptr; + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::BreakExpr (mapping, expr.get_locus (), + std ::move (break_label), + std::unique_ptr (break_expr), + expr.get_outer_attrs ()); + } + + void visit (AST::ContinueExpr &expr) override + { + HIR::Lifetime break_label = lower_lifetime (expr.get_label ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::ContinueExpr (mapping, expr.get_locus (), + std ::move (break_label), + expr.get_outer_attrs ()); + } + + void visit (AST::BorrowExpr &expr) override + { + HIR::Expr *borrow_lvalue + = ASTLoweringExpr::translate (expr.get_borrowed_expr ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::BorrowExpr ( + mapping, std::unique_ptr (borrow_lvalue), + expr.get_is_mut () ? Mutability::Mut : Mutability::Imm, + expr.get_is_double_borrow (), expr.get_outer_attrs (), expr.get_locus ()); + } + + void visit (AST::DereferenceExpr &expr) override + { + HIR::Expr *dref_lvalue + = ASTLoweringExpr::translate (expr.get_dereferenced_expr ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::DereferenceExpr (mapping, + std::unique_ptr (dref_lvalue), + expr.get_outer_attrs (), expr.get_locus ()); + } + + void visit (AST::MatchExpr &expr) override + { + translated = ASTLoweringExprWithBlock::translate (&expr, &terminated); + } + + void visit (AST::RangeFromToExpr &expr) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + HIR::Expr *range_from + = ASTLoweringExpr::translate (expr.get_from_expr ().get ()); + HIR::Expr *range_to + = ASTLoweringExpr::translate (expr.get_to_expr ().get ()); + + translated + = new HIR::RangeFromToExpr (mapping, + std::unique_ptr (range_from), + std::unique_ptr (range_to), + expr.get_locus ()); + } + + void visit (AST::RangeFromExpr &expr) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + HIR::Expr *range_from + = ASTLoweringExpr::translate (expr.get_from_expr ().get ()); + + translated + = new HIR::RangeFromExpr (mapping, + std::unique_ptr (range_from), + expr.get_locus ()); + } + + void visit (AST::RangeToExpr &expr) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + HIR::Expr *range_to + = ASTLoweringExpr::translate (expr.get_to_expr ().get ()); + + translated + = new HIR::RangeToExpr (mapping, std::unique_ptr (range_to), + expr.get_locus ()); + } + + void visit (AST::RangeFullExpr &expr) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::RangeFullExpr (mapping, expr.get_locus ()); + } + + void visit (AST::RangeFromToInclExpr &expr) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + HIR::Expr *range_from + = ASTLoweringExpr::translate (expr.get_from_expr ().get ()); + HIR::Expr *range_to + = ASTLoweringExpr::translate (expr.get_to_expr ().get ()); + + translated + = new HIR::RangeFromToInclExpr (mapping, + std::unique_ptr (range_from), + std::unique_ptr (range_to), + expr.get_locus ()); + } + +private: + ASTLoweringExpr () + : ASTLoweringBase (), translated (nullptr), + translated_array_elems (nullptr), terminated (false) + {} + + HIR::Expr *translated; + HIR::ArrayElems *translated_array_elems; + bool terminated; +}; + +} // namespace HIR +} // namespace Rust + +#endif // RUST_AST_LOWER_EXPR diff --git a/gcc/rust/hir/rust-ast-lower-extern.h b/gcc/rust/hir/rust-ast-lower-extern.h new file mode 100644 index 00000000000..eeb59c9c5d6 --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower-extern.h @@ -0,0 +1,121 @@ +// 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_LOWER_EXTERN_ITEM +#define RUST_AST_LOWER_EXTERN_ITEM + +#include "rust-ast-lower-base.h" +#include "rust-ast-lower-type.h" +#include "rust-ast-lower.h" + +namespace Rust { +namespace HIR { + +class ASTLoweringExternItem : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::ExternalItem *translate (AST::ExternalItem *item, + HirId parent_hirid) + { + ASTLoweringExternItem resolver; + item->accept_vis (resolver); + + rust_assert (resolver.translated != nullptr); + resolver.mappings->insert_hir_extern_item (resolver.translated, + parent_hirid); + resolver.mappings->insert_location ( + resolver.translated->get_mappings ().get_hirid (), + resolver.translated->get_locus ()); + + return resolver.translated; + } + + void visit (AST::ExternalStaticItem &item) override + { + HIR::Visibility vis = translate_visibility (item.get_visibility ()); + HIR::Type *static_type + = ASTLoweringType::translate (item.get_type ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, item.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::ExternalStaticItem ( + mapping, item.get_identifier (), std::unique_ptr (static_type), + item.is_mut () ? Mutability::Mut : Mutability::Imm, std::move (vis), + item.get_outer_attrs (), item.get_locus ()); + } + + void visit (AST::ExternalFunctionItem &function) override + { + std::vector > where_clause_items; + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::Visibility vis = translate_visibility (function.get_visibility ()); + + std::vector > generic_params; + if (function.has_generics ()) + generic_params = lower_generic_params (function.get_generic_params ()); + + HIR::Type *return_type + = function.has_return_type () + ? ASTLoweringType::translate (function.get_return_type ().get ()) + : nullptr; + + std::vector function_params; + for (auto ¶m : function.get_function_params ()) + { + HIR::Type *param_type + = ASTLoweringType::translate (param.get_type ().get ()); + Identifier param_name = param.get_name (); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, param.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id ( + crate_num)); + + function_params.push_back ( + HIR::NamedFunctionParam (mapping, param_name, + std::unique_ptr (param_type))); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, function.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::ExternalFunctionItem ( + mapping, function.get_identifier (), std::move (generic_params), + std::unique_ptr (return_type), std::move (where_clause), + std::move (function_params), function.is_variadic (), std::move (vis), + function.get_outer_attrs (), function.get_locus ()); + } + +private: + ASTLoweringExternItem () : translated (nullptr) {} + + HIR::ExternalItem *translated; +}; + +} // namespace HIR +} // namespace Rust + +#endif // RUST_AST_LOWER_ITEM diff --git a/gcc/rust/hir/rust-ast-lower-implitem.h b/gcc/rust/hir/rust-ast-lower-implitem.h new file mode 100644 index 00000000000..d5ca47587fc --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower-implitem.h @@ -0,0 +1,521 @@ +// 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_LOWER_IMPLITEM_H +#define RUST_AST_LOWER_IMPLITEM_H + +#include "rust-diagnostics.h" +#include "rust-ast-lower-type.h" +#include "rust-ast-lower-stmt.h" +#include "rust-ast-lower-expr.h" +#include "rust-ast-lower-pattern.h" +#include "rust-ast-lower-block.h" + +namespace Rust { +namespace HIR { + +class ASTLowerImplItem : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::ImplItem *translate (AST::InherentImplItem *item, + HirId parent_impl_id) + { + ASTLowerImplItem resolver; + item->accept_vis (resolver); + + if (resolver.translated != nullptr) + { + rust_assert (resolver.item_cast != nullptr); + + auto id = resolver.translated->get_impl_mappings ().get_hirid (); + auto defid = resolver.translated->get_impl_mappings ().get_defid (); + auto locus = resolver.translated->get_locus (); + + resolver.handle_outer_attributes (*resolver.item_cast); + resolver.mappings->insert_hir_implitem (parent_impl_id, + resolver.translated); + resolver.mappings->insert_location (id, locus); + resolver.mappings->insert_defid_mapping (defid, resolver.item_cast); + } + + return resolver.translated; + } + + static HIR::ImplItem *translate (AST::TraitImplItem *item, + HirId parent_impl_id) + { + ASTLowerImplItem resolver; + item->accept_vis (resolver); + + if (resolver.translated != nullptr) + { + rust_assert (resolver.item_cast != nullptr); + + auto id = resolver.translated->get_impl_mappings ().get_hirid (); + auto defid = resolver.translated->get_impl_mappings ().get_defid (); + auto locus = resolver.translated->get_locus (); + + resolver.handle_outer_attributes (*resolver.item_cast); + resolver.mappings->insert_hir_implitem (parent_impl_id, + resolver.translated); + resolver.mappings->insert_location (id, locus); + resolver.mappings->insert_defid_mapping (defid, resolver.item_cast); + } + + return resolver.translated; + } + + void visit (AST::TypeAlias &alias) override + { + std::vector > where_clause_items; + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::Visibility vis = translate_visibility (alias.get_visibility ()); + + std::vector > generic_params; + if (alias.has_generics ()) + generic_params = lower_generic_params (alias.get_generic_params ()); + + HIR::Type *existing_type + = ASTLoweringType::translate (alias.get_type_aliased ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, alias.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + auto type_alias = new HIR::TypeAlias ( + mapping, alias.get_new_type_name (), std::move (generic_params), + std::move (where_clause), std::unique_ptr (existing_type), + std::move (vis), alias.get_outer_attrs (), alias.get_locus ()); + + translated = type_alias; + item_cast = type_alias; + } + + void visit (AST::ConstantItem &constant) override + { + HIR::Visibility vis = translate_visibility (constant.get_visibility ()); + + HIR::Type *type = ASTLoweringType::translate (constant.get_type ().get ()); + HIR::Expr *expr = ASTLoweringExpr::translate (constant.get_expr ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, constant.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + auto translated_constant + = new HIR::ConstantItem (mapping, constant.get_identifier (), vis, + std::unique_ptr (type), + std::unique_ptr (expr), + constant.get_outer_attrs (), + constant.get_locus ()); + translated = translated_constant; + item_cast = translated_constant; + } + + void visit (AST::Function &function) override + { + // ignore for now and leave empty + std::vector > where_clause_items; + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::FunctionQualifiers qualifiers + = lower_qualifiers (function.get_qualifiers ()); + HIR::Visibility vis = translate_visibility (function.get_visibility ()); + + // need + std::vector > generic_params; + if (function.has_generics ()) + { + generic_params = lower_generic_params (function.get_generic_params ()); + } + Identifier function_name = function.get_function_name (); + Location locus = function.get_locus (); + + std::unique_ptr return_type + = function.has_return_type () ? std::unique_ptr ( + ASTLoweringType::translate (function.get_return_type ().get ())) + : nullptr; + + std::vector function_params; + for (auto ¶m : function.get_function_params ()) + { + auto translated_pattern = std::unique_ptr ( + ASTLoweringPattern::translate (param.get_pattern ().get ())); + auto translated_type = std::unique_ptr ( + ASTLoweringType::translate (param.get_type ().get ())); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, param.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + auto hir_param + = HIR::FunctionParam (mapping, std::move (translated_pattern), + std::move (translated_type), + param.get_locus ()); + function_params.push_back (std::move (hir_param)); + } + + bool terminated = false; + std::unique_ptr function_body + = std::unique_ptr ( + ASTLoweringBlock::translate (function.get_definition ().get (), + &terminated)); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, function.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + mappings->insert_location (function_body->get_mappings ().get_hirid (), + function.get_locus ()); + + auto fn + = new HIR::Function (mapping, std::move (function_name), + std::move (qualifiers), std::move (generic_params), + std::move (function_params), std::move (return_type), + std::move (where_clause), std::move (function_body), + std::move (vis), function.get_outer_attrs (), + HIR::SelfParam::error (), locus); + + // add the mappings for the function params at the end + for (auto ¶m : fn->get_function_params ()) + { + mappings->insert_hir_param (¶m); + mappings->insert_location (mapping.get_hirid (), param.get_locus ()); + } + + translated = fn; + item_cast = fn; + } + + void visit (AST::Method &method) override + { + // ignore for now and leave empty + std::vector > where_clause_items; + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::FunctionQualifiers qualifiers + = lower_qualifiers (method.get_qualifiers ()); + HIR::Visibility vis = translate_visibility (method.get_visibility ()); + + // need + std::vector > generic_params; + if (method.has_generics ()) + { + generic_params = lower_generic_params (method.get_generic_params ()); + } + Identifier method_name = method.get_method_name (); + Location locus = method.get_locus (); + + HIR::SelfParam self_param = lower_self (method.get_self_param ()); + + std::unique_ptr return_type + = method.has_return_type () ? std::unique_ptr ( + ASTLoweringType::translate (method.get_return_type ().get ())) + : nullptr; + + std::vector function_params; + for (auto ¶m : method.get_function_params ()) + { + auto translated_pattern = std::unique_ptr ( + ASTLoweringPattern::translate (param.get_pattern ().get ())); + auto translated_type = std::unique_ptr ( + ASTLoweringType::translate (param.get_type ().get ())); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, param.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + auto hir_param + = HIR::FunctionParam (mapping, std::move (translated_pattern), + std::move (translated_type), + param.get_locus ()); + function_params.push_back (std::move (hir_param)); + } + + bool terminated = false; + std::unique_ptr method_body + = std::unique_ptr ( + ASTLoweringBlock::translate (method.get_definition ().get (), + &terminated)); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, method.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + auto mth + = new HIR::Function (mapping, std::move (method_name), + std::move (qualifiers), std::move (generic_params), + std::move (function_params), std::move (return_type), + std::move (where_clause), std::move (method_body), + std::move (vis), method.get_outer_attrs (), + std::move (self_param), locus); + + // insert mappings for self + mappings->insert_hir_self_param (&self_param); + mappings->insert_location (self_param.get_mappings ().get_hirid (), + self_param.get_locus ()); + + // add the mappings for the function params at the end + for (auto ¶m : mth->get_function_params ()) + { + mappings->insert_hir_param (¶m); + mappings->insert_location (mapping.get_hirid (), param.get_locus ()); + } + + translated = mth; + item_cast = mth; + } + +private: + ASTLowerImplItem () : translated (nullptr), item_cast (nullptr) {} + + HIR::ImplItem *translated; + HIR::Item *item_cast; +}; + +class ASTLowerTraitItem : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::TraitItem *translate (AST::TraitItem *item) + { + ASTLowerTraitItem resolver; + item->accept_vis (resolver); + + if (resolver.translated != nullptr) + { + // FIXME + + // auto id = resolver.translated->get_mappings ().get_hirid (); + // auto defid = resolver.translated->get_mappings ().get_defid (); + // auto locus = resolver.translated->get_locus (); + + // resolver.handle_outer_attributes (*resolver.translated); + resolver.mappings->insert_hir_trait_item (resolver.translated); + // resolver.mappings->insert_location (id, locus); + // resolver.mappings->insert_defid_mapping (defid, resolver.item_cast); + } + + return resolver.translated; + } + + void visit (AST::TraitItemFunc &func) override + { + AST::TraitFunctionDecl &ref = func.get_trait_function_decl (); + + std::vector > where_clause_items; + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::FunctionQualifiers qualifiers + = lower_qualifiers (func.get_trait_function_decl ().get_qualifiers ()); + + std::vector > generic_params; + if (ref.has_generics ()) + { + generic_params = lower_generic_params (ref.get_generic_params ()); + } + + std::unique_ptr return_type + = ref.has_return_type () ? std::unique_ptr ( + ASTLoweringType::translate (ref.get_return_type ().get ())) + : nullptr; + + std::vector function_params; + for (auto ¶m : ref.get_function_params ()) + { + auto translated_pattern = std::unique_ptr ( + ASTLoweringPattern::translate (param.get_pattern ().get ())); + auto translated_type = std::unique_ptr ( + ASTLoweringType::translate (param.get_type ().get ())); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, param.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + auto hir_param + = HIR::FunctionParam (mapping, std::move (translated_pattern), + std::move (translated_type), + param.get_locus ()); + function_params.push_back (std::move (hir_param)); + } + + HIR::TraitFunctionDecl decl (ref.get_identifier (), std::move (qualifiers), + std::move (generic_params), + HIR::SelfParam::error (), + std::move (function_params), + std::move (return_type), + std::move (where_clause)); + bool terminated = false; + std::unique_ptr block_expr + = func.has_definition () ? std::unique_ptr ( + ASTLoweringBlock::translate (func.get_definition ().get (), + &terminated)) + : nullptr; + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, func.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + HIR::TraitItemFunc *trait_item + = new HIR::TraitItemFunc (mapping, std::move (decl), + std::move (block_expr), func.get_outer_attrs (), + func.get_locus ()); + translated = trait_item; + + // add the mappings for the function params at the end + for (auto ¶m : trait_item->get_decl ().get_function_params ()) + { + mappings->insert_hir_param (¶m); + mappings->insert_location (mapping.get_hirid (), param.get_locus ()); + } + } + + void visit (AST::TraitItemMethod &method) override + { + AST::TraitMethodDecl &ref = method.get_trait_method_decl (); + + std::vector > where_clause_items; + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::FunctionQualifiers qualifiers + = lower_qualifiers (method.get_trait_method_decl ().get_qualifiers ()); + + std::vector > generic_params; + if (ref.has_generics ()) + { + generic_params = lower_generic_params (ref.get_generic_params ()); + } + + std::unique_ptr return_type + = ref.has_return_type () ? std::unique_ptr ( + ASTLoweringType::translate (ref.get_return_type ().get ())) + : nullptr; + + HIR::SelfParam self_param = lower_self (ref.get_self_param ()); + + std::vector function_params; + for (auto ¶m : ref.get_function_params ()) + { + auto translated_pattern = std::unique_ptr ( + ASTLoweringPattern::translate (param.get_pattern ().get ())); + auto translated_type = std::unique_ptr ( + ASTLoweringType::translate (param.get_type ().get ())); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, param.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + auto hir_param + = HIR::FunctionParam (mapping, std::move (translated_pattern), + std::move (translated_type), + param.get_locus ()); + function_params.push_back (hir_param); + } + + HIR::TraitFunctionDecl decl (ref.get_identifier (), std::move (qualifiers), + std::move (generic_params), + std::move (self_param), + std::move (function_params), + std::move (return_type), + std::move (where_clause)); + bool terminated = false; + std::unique_ptr block_expr + = method.has_definition () ? std::unique_ptr ( + ASTLoweringBlock::translate (method.get_definition ().get (), + &terminated)) + : nullptr; + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, method.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + HIR::TraitItemFunc *trait_item + = new HIR::TraitItemFunc (mapping, std::move (decl), + std::move (block_expr), + method.get_outer_attrs (), method.get_locus ()); + translated = trait_item; + + // insert mappings for self + mappings->insert_hir_self_param (&self_param); + mappings->insert_location (self_param.get_mappings ().get_hirid (), + self_param.get_locus ()); + + // add the mappings for the function params at the end + for (auto ¶m : trait_item->get_decl ().get_function_params ()) + { + mappings->insert_hir_param (¶m); + mappings->insert_location (mapping.get_hirid (), param.get_locus ()); + } + } + + void visit (AST::TraitItemConst &constant) override + { + HIR::Type *type = ASTLoweringType::translate (constant.get_type ().get ()); + HIR::Expr *expr + = constant.has_expression () + ? ASTLoweringExpr::translate (constant.get_expr ().get ()) + : nullptr; + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, constant.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + HIR::TraitItemConst *trait_item + = new HIR::TraitItemConst (mapping, constant.get_identifier (), + std::unique_ptr (type), + std::unique_ptr (expr), + constant.get_outer_attrs (), + constant.get_locus ()); + translated = trait_item; + } + + void visit (AST::TraitItemType &type) override + { + std::vector > type_param_bounds; + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, type.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + HIR::TraitItemType *trait_item + = new HIR::TraitItemType (mapping, type.get_identifier (), + std::move (type_param_bounds), + type.get_outer_attrs (), type.get_locus ()); + translated = trait_item; + } + +private: + ASTLowerTraitItem () : translated (nullptr) {} + + HIR::TraitItem *translated; +}; + +} // namespace HIR +} // namespace Rust + +#endif // RUST_AST_LOWER_IMPLITEM_H diff --git a/gcc/rust/hir/rust-ast-lower-item.cc b/gcc/rust/hir/rust-ast-lower-item.cc new file mode 100644 index 00000000000..fefc938b8e5 --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower-item.cc @@ -0,0 +1,741 @@ +// 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 +// . + +#include "rust-ast-lower-item.h" + +namespace Rust { +namespace HIR { + +HIR::Item * +ASTLoweringItem::translate (AST::Item *item) +{ + ASTLoweringItem resolver; + item->accept_vis (resolver); + + if (resolver.translated != nullptr) + { + auto id = resolver.translated->get_mappings ().get_hirid (); + auto defid = resolver.translated->get_mappings ().get_defid (); + auto locus = resolver.translated->get_locus (); + + resolver.handle_outer_attributes (*resolver.translated); + resolver.mappings->insert_ast_item (item); + resolver.mappings->insert_hir_item (resolver.translated); + resolver.mappings->insert_location (id, locus); + resolver.mappings->insert_defid_mapping (defid, resolver.translated); + } + + return resolver.translated; +} + +void +ASTLoweringItem::visit (AST::Module &module) +{ + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, module.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + // should be lowered from module.get_vis() + HIR::Visibility vis = translate_visibility (module.get_visibility ()); + + auto items = std::vector> (); + + for (auto &item : module.get_items ()) + { + auto transitem = translate (item.get ()); + items.push_back (std::unique_ptr (transitem)); + } + + // should be lowered/copied from module.get_in/outer_attrs() + AST::AttrVec inner_attrs = module.get_inner_attrs (); + AST::AttrVec outer_attrs = module.get_outer_attrs (); + + translated + = new HIR::Module (mapping, module.get_name (), module.get_locus (), + std::move (items), std::move (vis), + std::move (inner_attrs), std::move (outer_attrs)); + mappings->insert_module (static_cast (translated)); +} + +void +ASTLoweringItem::visit (AST::TypeAlias &alias) +{ + std::vector> where_clause_items; + for (auto &item : alias.get_where_clause ().get_items ()) + { + HIR::WhereClauseItem *i + = ASTLowerWhereClauseItem::translate (*item.get ()); + where_clause_items.push_back (std::unique_ptr (i)); + } + + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::Visibility vis = translate_visibility (alias.get_visibility ()); + + std::vector> generic_params; + if (alias.has_generics ()) + generic_params = lower_generic_params (alias.get_generic_params ()); + + HIR::Type *existing_type + = ASTLoweringType::translate (alias.get_type_aliased ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, alias.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated + = new HIR::TypeAlias (mapping, alias.get_new_type_name (), + std::move (generic_params), std::move (where_clause), + std::unique_ptr (existing_type), + std::move (vis), alias.get_outer_attrs (), + alias.get_locus ()); +} + +void +ASTLoweringItem::visit (AST::TupleStruct &struct_decl) +{ + std::vector> generic_params; + if (struct_decl.has_generics ()) + { + generic_params = lower_generic_params (struct_decl.get_generic_params ()); + } + + std::vector> where_clause_items; + for (auto &item : struct_decl.get_where_clause ().get_items ()) + { + HIR::WhereClauseItem *i + = ASTLowerWhereClauseItem::translate (*item.get ()); + where_clause_items.push_back (std::unique_ptr (i)); + } + + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::Visibility vis = translate_visibility (struct_decl.get_visibility ()); + + std::vector fields; + for (AST::TupleField &field : struct_decl.get_fields ()) + { + if (field.get_field_type ()->is_marked_for_strip ()) + continue; + + // FIXME: How do we get the visibility from here? + HIR::Visibility vis = translate_visibility (field.get_visibility ()); + HIR::Type *type + = ASTLoweringType::translate (field.get_field_type ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, field.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id ( + crate_num)); + + HIR::TupleField translated_field (mapping, + std::unique_ptr (type), vis, + field.get_locus (), + field.get_outer_attrs ()); + fields.push_back (std::move (translated_field)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, struct_decl.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::TupleStruct (mapping, std::move (fields), + struct_decl.get_identifier (), + std::move (generic_params), + std::move (where_clause), vis, + struct_decl.get_outer_attrs (), + struct_decl.get_locus ()); +} + +void +ASTLoweringItem::visit (AST::StructStruct &struct_decl) +{ + std::vector> generic_params; + if (struct_decl.has_generics ()) + { + generic_params = lower_generic_params (struct_decl.get_generic_params ()); + } + + std::vector> where_clause_items; + for (auto &item : struct_decl.get_where_clause ().get_items ()) + { + HIR::WhereClauseItem *i + = ASTLowerWhereClauseItem::translate (*item.get ()); + where_clause_items.push_back (std::unique_ptr (i)); + } + + HIR::WhereClause where_clause (std::move (where_clause_items)); + + HIR::Visibility vis = translate_visibility (struct_decl.get_visibility ()); + + bool is_unit = struct_decl.is_unit_struct (); + std::vector fields; + for (AST::StructField &field : struct_decl.get_fields ()) + { + if (field.get_field_type ()->is_marked_for_strip ()) + continue; + + HIR::Visibility vis = translate_visibility (field.get_visibility ()); + HIR::Type *type + = ASTLoweringType::translate (field.get_field_type ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, field.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id ( + crate_num)); + + HIR::StructField translated_field (mapping, field.get_field_name (), + std::unique_ptr (type), vis, + field.get_locus (), + field.get_outer_attrs ()); + + if (struct_field_name_exists (fields, translated_field)) + break; + + fields.push_back (std::move (translated_field)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, struct_decl.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::StructStruct (mapping, std::move (fields), + struct_decl.get_identifier (), + std::move (generic_params), + std::move (where_clause), is_unit, vis, + struct_decl.get_outer_attrs (), + struct_decl.get_locus ()); +} + +void +ASTLoweringItem::visit (AST::Enum &enum_decl) +{ + std::vector> generic_params; + if (enum_decl.has_generics ()) + { + generic_params = lower_generic_params (enum_decl.get_generic_params ()); + } + + std::vector> where_clause_items; + for (auto &item : enum_decl.get_where_clause ().get_items ()) + { + HIR::WhereClauseItem *i + = ASTLowerWhereClauseItem::translate (*item.get ()); + where_clause_items.push_back (std::unique_ptr (i)); + } + + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::Visibility vis = translate_visibility (enum_decl.get_visibility ()); + + // bool is_unit = enum_decl.is_zero_variant (); + std::vector> items; + for (auto &variant : enum_decl.get_variants ()) + { + if (variant->is_marked_for_strip ()) + continue; + + HIR::EnumItem *hir_item = ASTLoweringEnumItem::translate (variant.get ()); + items.push_back (std::unique_ptr (hir_item)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, enum_decl.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::Enum (mapping, enum_decl.get_identifier (), vis, + std::move (generic_params), + std::move (where_clause), /* is_unit, */ + std::move (items), enum_decl.get_outer_attrs (), + enum_decl.get_locus ()); +} + +void +ASTLoweringItem::visit (AST::Union &union_decl) +{ + std::vector> generic_params; + if (union_decl.has_generics ()) + { + generic_params = lower_generic_params (union_decl.get_generic_params ()); + } + + std::vector> where_clause_items; + for (auto &item : union_decl.get_where_clause ().get_items ()) + { + HIR::WhereClauseItem *i + = ASTLowerWhereClauseItem::translate (*item.get ()); + where_clause_items.push_back (std::unique_ptr (i)); + } + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::Visibility vis = translate_visibility (union_decl.get_visibility ()); + + std::vector variants; + for (AST::StructField &variant : union_decl.get_variants ()) + { + if (variant.get_field_type ()->is_marked_for_strip ()) + continue; + + // FIXME: Does visibility apply here? + HIR::Visibility vis = translate_visibility (variant.get_visibility ()); + HIR::Type *type + = ASTLoweringType::translate (variant.get_field_type ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, variant.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id ( + crate_num)); + + HIR::StructField translated_variant (mapping, variant.get_field_name (), + std::unique_ptr (type), + vis, variant.get_locus (), + variant.get_outer_attrs ()); + + if (struct_field_name_exists (variants, translated_variant)) + break; + + variants.push_back (std::move (translated_variant)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, union_decl.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated + = new HIR::Union (mapping, union_decl.get_identifier (), vis, + std::move (generic_params), std::move (where_clause), + std::move (variants), union_decl.get_outer_attrs (), + union_decl.get_locus ()); +} + +void +ASTLoweringItem::visit (AST::StaticItem &var) +{ + HIR::Visibility vis = translate_visibility (var.get_visibility ()); + + HIR::Type *type = ASTLoweringType::translate (var.get_type ().get ()); + HIR::Expr *expr = ASTLoweringExpr::translate (var.get_expr ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, var.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::StaticItem (mapping, var.get_identifier (), + var.is_mutable () ? Mutability::Mut + : Mutability::Imm, + std::unique_ptr (type), + std::unique_ptr (expr), vis, + var.get_outer_attrs (), var.get_locus ()); +} + +void +ASTLoweringItem::visit (AST::ConstantItem &constant) +{ + HIR::Visibility vis = translate_visibility (constant.get_visibility ()); + + HIR::Type *type = ASTLoweringType::translate (constant.get_type ().get ()); + HIR::Expr *expr = ASTLoweringExpr::translate (constant.get_expr ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, constant.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::ConstantItem (mapping, constant.get_identifier (), vis, + std::unique_ptr (type), + std::unique_ptr (expr), + constant.get_outer_attrs (), + constant.get_locus ()); +} + +void +ASTLoweringItem::visit (AST::Function &function) +{ + if (function.is_marked_for_strip ()) + return; + + std::vector> where_clause_items; + for (auto &item : function.get_where_clause ().get_items ()) + { + HIR::WhereClauseItem *i + = ASTLowerWhereClauseItem::translate (*item.get ()); + where_clause_items.push_back (std::unique_ptr (i)); + } + + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::FunctionQualifiers qualifiers + = lower_qualifiers (function.get_qualifiers ()); + HIR::Visibility vis = translate_visibility (function.get_visibility ()); + + // need + std::vector> generic_params; + if (function.has_generics ()) + { + generic_params = lower_generic_params (function.get_generic_params ()); + } + Identifier function_name = function.get_function_name (); + Location locus = function.get_locus (); + + std::unique_ptr return_type + = function.has_return_type () ? std::unique_ptr ( + ASTLoweringType::translate (function.get_return_type ().get ())) + : nullptr; + + std::vector function_params; + for (auto ¶m : function.get_function_params ()) + { + auto translated_pattern = std::unique_ptr ( + ASTLoweringPattern::translate (param.get_pattern ().get ())); + auto translated_type = std::unique_ptr ( + ASTLoweringType::translate (param.get_type ().get ())); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, param.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + auto hir_param + = HIR::FunctionParam (mapping, std::move (translated_pattern), + std::move (translated_type), param.get_locus ()); + function_params.push_back (std::move (hir_param)); + } + + bool terminated = false; + std::unique_ptr function_body + = std::unique_ptr ( + ASTLoweringBlock::translate (function.get_definition ().get (), + &terminated)); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, function.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + mappings->insert_location (function_body->get_mappings ().get_hirid (), + function.get_locus ()); + + auto fn + = new HIR::Function (mapping, std::move (function_name), + std::move (qualifiers), std::move (generic_params), + std::move (function_params), std::move (return_type), + std::move (where_clause), std::move (function_body), + std::move (vis), function.get_outer_attrs (), + HIR::SelfParam::error (), locus); + + // add the mappings for the function params at the end + for (auto ¶m : fn->get_function_params ()) + { + mappings->insert_hir_param (¶m); + mappings->insert_location (mapping.get_hirid (), param.get_locus ()); + } + + translated = fn; +} + +void +ASTLoweringItem::visit (AST::InherentImpl &impl_block) +{ + std::vector> where_clause_items; + for (auto &item : impl_block.get_where_clause ().get_items ()) + { + HIR::WhereClauseItem *i + = ASTLowerWhereClauseItem::translate (*item.get ()); + where_clause_items.push_back (std::unique_ptr (i)); + } + + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::Visibility vis = translate_visibility (impl_block.get_visibility ()); + + std::vector> generic_params; + if (impl_block.has_generics ()) + { + generic_params = lower_generic_params (impl_block.get_generic_params ()); + + for (auto &generic_param : generic_params) + { + switch (generic_param->get_kind ()) + { + case HIR::GenericParam::GenericKind::TYPE: { + const HIR::TypeParam &t + = static_cast (*generic_param); + + if (t.has_type ()) + { + // see https://github.com/rust-lang/rust/issues/36887 + rust_error_at ( + t.get_locus (), + "defaults for type parameters are not allowed here"); + } + } + break; + + default: + break; + } + } + } + + HIR::Type *impl_type + = ASTLoweringType::translate (impl_block.get_type ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, impl_block.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + std::vector> impl_items; + std::vector impl_item_ids; + for (auto &impl_item : impl_block.get_impl_items ()) + { + if (impl_item->is_marked_for_strip ()) + continue; + + HIR::ImplItem *lowered + = ASTLowerImplItem::translate (impl_item.get (), mapping.get_hirid ()); + rust_assert (lowered != nullptr); + impl_items.push_back (std::unique_ptr (lowered)); + impl_item_ids.push_back (lowered->get_impl_mappings ().get_hirid ()); + } + + Polarity polarity = Positive; + HIR::ImplBlock *hir_impl_block = new HIR::ImplBlock ( + mapping, std::move (impl_items), std::move (generic_params), + std::unique_ptr (impl_type), nullptr, where_clause, polarity, + vis, impl_block.get_inner_attrs (), impl_block.get_outer_attrs (), + impl_block.get_locus ()); + translated = hir_impl_block; + + mappings->insert_hir_impl_block (hir_impl_block); + for (auto &impl_item_id : impl_item_ids) + { + mappings->insert_impl_item_mapping (impl_item_id, hir_impl_block); + } +} + +void +ASTLoweringItem::visit (AST::Trait &trait) +{ + std::vector> where_clause_items; + for (auto &item : trait.get_where_clause ().get_items ()) + { + HIR::WhereClauseItem *i + = ASTLowerWhereClauseItem::translate (*item.get ()); + where_clause_items.push_back (std::unique_ptr (i)); + } + HIR::WhereClause where_clause (std::move (where_clause_items)); + + HIR::Visibility vis = translate_visibility (trait.get_visibility ()); + + std::vector> generic_params; + if (trait.has_generics ()) + { + generic_params = lower_generic_params (trait.get_generic_params ()); + } + + std::vector> type_param_bounds; + if (trait.has_type_param_bounds ()) + { + for (auto &bound : trait.get_type_param_bounds ()) + { + HIR::TypeParamBound *b = lower_bound (bound.get ()); + type_param_bounds.push_back ( + std::unique_ptr (b)); + } + } + + std::vector> trait_items; + std::vector trait_item_ids; + for (auto &item : trait.get_trait_items ()) + { + if (item->is_marked_for_strip ()) + continue; + + HIR::TraitItem *lowered = ASTLowerTraitItem::translate (item.get ()); + trait_items.push_back (std::unique_ptr (lowered)); + trait_item_ids.push_back (lowered->get_mappings ().get_hirid ()); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, trait.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + auto trait_unsafety = Unsafety::Normal; + if (trait.is_unsafe ()) + { + trait_unsafety = Unsafety::Unsafe; + } + + HIR::Trait *hir_trait + = new HIR::Trait (mapping, trait.get_identifier (), trait_unsafety, + std::move (generic_params), std::move (type_param_bounds), + where_clause, std::move (trait_items), vis, + trait.get_outer_attrs (), trait.get_locus ()); + translated = hir_trait; + + for (auto trait_item_id : trait_item_ids) + { + mappings->insert_trait_item_mapping (trait_item_id, hir_trait); + } +} + +void +ASTLoweringItem::visit (AST::TraitImpl &impl_block) +{ + std::vector> where_clause_items; + for (auto &item : impl_block.get_where_clause ().get_items ()) + { + HIR::WhereClauseItem *i + = ASTLowerWhereClauseItem::translate (*item.get ()); + where_clause_items.push_back (std::unique_ptr (i)); + } + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::Visibility vis = translate_visibility (impl_block.get_visibility ()); + + std::vector> generic_params; + if (impl_block.has_generics ()) + { + generic_params = lower_generic_params (impl_block.get_generic_params ()); + + for (auto &generic_param : generic_params) + { + switch (generic_param->get_kind ()) + { + case HIR::GenericParam::GenericKind::TYPE: { + const HIR::TypeParam &t + = static_cast (*generic_param); + + if (t.has_type ()) + { + // see https://github.com/rust-lang/rust/issues/36887 + rust_error_at ( + t.get_locus (), + "defaults for type parameters are not allowed here"); + } + } + break; + + default: + break; + } + } + } + + HIR::Type *impl_type + = ASTLoweringType::translate (impl_block.get_type ().get ()); + HIR::TypePath *trait_ref + = ASTLowerTypePath::translate (impl_block.get_trait_path ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, impl_block.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + std::vector> impl_items; + std::vector impl_item_ids; + for (auto &impl_item : impl_block.get_impl_items ()) + { + if (impl_item->is_marked_for_strip ()) + continue; + + HIR::ImplItem *lowered + = ASTLowerImplItem::translate (impl_item.get (), mapping.get_hirid ()); + rust_assert (lowered != nullptr); + impl_items.push_back (std::unique_ptr (lowered)); + impl_item_ids.push_back (lowered->get_impl_mappings ().get_hirid ()); + } + + Polarity polarity = impl_block.is_exclam () ? Positive : Negative; + HIR::ImplBlock *hir_impl_block = new HIR::ImplBlock ( + mapping, std::move (impl_items), std::move (generic_params), + std::unique_ptr (impl_type), + std::unique_ptr (trait_ref), where_clause, polarity, vis, + impl_block.get_inner_attrs (), impl_block.get_outer_attrs (), + impl_block.get_locus ()); + translated = hir_impl_block; + + mappings->insert_hir_impl_block (hir_impl_block); + for (auto &impl_item_id : impl_item_ids) + { + mappings->insert_impl_item_mapping (impl_item_id, hir_impl_block); + } +} + +void +ASTLoweringItem::visit (AST::ExternBlock &extern_block) +{ + translated = lower_extern_block (extern_block); +} + +HIR::SimplePath +ASTLoweringSimplePath::translate (const AST::SimplePath &path) +{ + ASTLoweringSimplePath resolver; + + return resolver.lower (path); +} + +HIR::SimplePathSegment +ASTLoweringSimplePath::lower (const AST::SimplePathSegment &segment) +{ + auto crate_num = mappings->get_current_crate (); + auto node_id = segment.get_node_id (); + + auto mapping = Analysis::NodeMapping (crate_num, node_id, + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + auto hir_seg = HIR::SimplePathSegment (mapping); + + mappings->insert_node_to_hir (node_id, mapping.get_hirid ()); + // mappings->insert_simple_path_segment (crate_num, node_id, &segment); + + return hir_seg; +} + +HIR::SimplePath +ASTLoweringSimplePath::lower (const AST::SimplePath &path) +{ + auto segments = std::vector (); + for (auto &segment : path.get_segments ()) + segments.emplace_back (lower (segment)); + + auto crate_num = mappings->get_current_crate (); + auto node_id = path.get_node_id (); + + auto mapping = Analysis::NodeMapping (crate_num, node_id, + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + auto lowered + = HIR::SimplePath (std::move (segments), mapping, path.get_locus ()); + + mappings->insert_node_to_hir (node_id, mapping.get_hirid ()); + // mappings->insert_simple_path (crate_num, node_id, &path); + + return lowered; +} + +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/hir/rust-ast-lower-item.h b/gcc/rust/hir/rust-ast-lower-item.h new file mode 100644 index 00000000000..5d4ee18f517 --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower-item.h @@ -0,0 +1,78 @@ +// 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_LOWER_ITEM +#define RUST_AST_LOWER_ITEM + +#include "rust-diagnostics.h" + +#include "rust-ast-lower.h" +#include "rust-ast-lower-base.h" +#include "rust-ast-lower-enumitem.h" +#include "rust-ast-lower-type.h" +#include "rust-ast-lower-implitem.h" +#include "rust-ast-lower-stmt.h" +#include "rust-ast-lower-expr.h" +#include "rust-ast-lower-pattern.h" +#include "rust-ast-lower-block.h" +#include "rust-ast-lower-extern.h" +#include "rust-hir-full-decls.h" + +namespace Rust { +namespace HIR { + +class ASTLoweringItem : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::Item *translate (AST::Item *item); + + void visit (AST::Module &module) override; + void visit (AST::TypeAlias &alias) override; + void visit (AST::TupleStruct &struct_decl) override; + void visit (AST::StructStruct &struct_decl) override; + void visit (AST::Enum &enum_decl) override; + void visit (AST::Union &union_decl) override; + void visit (AST::StaticItem &var) override; + void visit (AST::ConstantItem &constant) override; + void visit (AST::Function &function) override; + void visit (AST::InherentImpl &impl_block) override; + void visit (AST::Trait &trait) override; + void visit (AST::TraitImpl &impl_block) override; + void visit (AST::ExternBlock &extern_block) override; + +private: + ASTLoweringItem () : translated (nullptr) {} + + HIR::Item *translated; +}; + +class ASTLoweringSimplePath : public ASTLoweringBase +{ +public: + static HIR::SimplePath translate (const AST::SimplePath &path); + + HIR::SimplePathSegment lower (const AST::SimplePathSegment &segment); + HIR::SimplePath lower (const AST::SimplePath &path); +}; + +} // namespace HIR +} // namespace Rust + +#endif // RUST_AST_LOWER_ITEM diff --git a/gcc/rust/hir/rust-ast-lower-pattern.cc b/gcc/rust/hir/rust-ast-lower-pattern.cc new file mode 100644 index 00000000000..2421ca84651 --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower-pattern.cc @@ -0,0 +1,229 @@ +// 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 +// . + +#include "rust-ast-lower-pattern.h" +#include "rust-ast-lower-expr.h" + +namespace Rust { +namespace HIR { + +void +ASTLoweringPattern::visit (AST::IdentifierPattern &pattern) +{ + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + std::unique_ptr to_bind; + translated + = new HIR::IdentifierPattern (mapping, pattern.get_ident (), + pattern.get_locus (), pattern.get_is_ref (), + pattern.get_is_mut () ? Mutability::Mut + : Mutability::Imm, + std::move (to_bind)); +} + +void +ASTLoweringPattern::visit (AST::PathInExpression &pattern) +{ + translated = ASTLowerPathInExpression::translate (&pattern); +} + +void +ASTLoweringPattern::visit (AST::TupleStructPattern &pattern) +{ + HIR::PathInExpression *path + = ASTLowerPathInExpression::translate (&pattern.get_path ()); + + TupleStructItems *lowered = nullptr; + auto &items = pattern.get_items (); + switch (items->get_item_type ()) + { + case AST::TupleStructItems::RANGE: { + // TODO + gcc_unreachable (); + } + break; + + case AST::TupleStructItems::NO_RANGE: { + AST::TupleStructItemsNoRange &items_no_range + = static_cast (*items.get ()); + + std::vector > patterns; + for (auto &inner_pattern : items_no_range.get_patterns ()) + { + HIR::Pattern *p + = ASTLoweringPattern::translate (inner_pattern.get ()); + patterns.push_back (std::unique_ptr (p)); + } + + lowered = new HIR::TupleStructItemsNoRange (std::move (patterns)); + } + break; + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::TupleStructPattern ( + mapping, *path, std::unique_ptr (lowered)); +} + +void +ASTLoweringPattern::visit (AST::StructPattern &pattern) +{ + HIR::PathInExpression *path + = ASTLowerPathInExpression::translate (&pattern.get_path ()); + + auto &raw_elems = pattern.get_struct_pattern_elems (); + rust_assert (!raw_elems.has_etc ()); + + std::vector > fields; + for (auto &field : raw_elems.get_struct_pattern_fields ()) + { + HIR::StructPatternField *f = nullptr; + switch (field->get_item_type ()) + { + case AST::StructPatternField::ItemType::TUPLE_PAT: { + // TODO + gcc_unreachable (); + } + break; + + case AST::StructPatternField::ItemType::IDENT_PAT: { + // TODO + gcc_unreachable (); + } + break; + + case AST::StructPatternField::ItemType::IDENT: { + AST::StructPatternFieldIdent &ident + = static_cast (*field.get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, ident.get_node_id (), + mappings->get_next_hir_id ( + crate_num), + UNKNOWN_LOCAL_DEFID); + + f = new HIR::StructPatternFieldIdent ( + mapping, ident.get_identifier (), ident.is_ref (), + ident.is_mut () ? Mutability::Mut : Mutability::Imm, + ident.get_outer_attrs (), ident.get_locus ()); + } + break; + } + + // insert the reverse mappings and locations + auto field_id = f->get_mappings ().get_hirid (); + auto field_node_id = f->get_mappings ().get_nodeid (); + mappings->insert_location (field_id, f->get_locus ()); + mappings->insert_node_to_hir (field_node_id, field_id); + + // add it to the lowered fields list + fields.push_back (std::unique_ptr (f)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + HIR::StructPatternElements elems (std::move (fields)); + translated = new HIR::StructPattern (mapping, *path, std::move (elems)); +} + +void +ASTLoweringPattern::visit (AST::WildcardPattern &pattern) +{ + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::WildcardPattern (mapping, pattern.get_locus ()); +} + +void +ASTLoweringPattern::visit (AST::TuplePattern &pattern) +{ + std::unique_ptr items; + switch (pattern.get_items ()->get_pattern_type ()) + { + case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: { + AST::TuplePatternItemsMultiple &ref + = *static_cast ( + pattern.get_items ().get ()); + items = lower_tuple_pattern_multiple (ref); + } + break; + + case AST::TuplePatternItems::TuplePatternItemType::RANGED: { + AST::TuplePatternItemsRanged &ref + = *static_cast ( + pattern.get_items ().get ()); + items = lower_tuple_pattern_ranged (ref); + } + break; + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::TuplePattern (mapping, std::move (items), pattern.get_locus ()); +} + +void +ASTLoweringPattern::visit (AST::LiteralPattern &pattern) +{ + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + HIR::Literal l = lower_literal (pattern.get_literal ()); + translated + = new HIR::LiteralPattern (mapping, std::move (l), pattern.get_locus ()); +} + +void +ASTLoweringPattern::visit (AST::RangePattern &pattern) +{ + auto upper_bound + = lower_range_pattern_bound (pattern.get_upper_bound ().get ()); + auto lower_bound + = lower_range_pattern_bound (pattern.get_lower_bound ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::RangePattern (mapping, std::move (lower_bound), + std::move (upper_bound), pattern.get_locus ()); +} + +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/hir/rust-ast-lower-pattern.h b/gcc/rust/hir/rust-ast-lower-pattern.h new file mode 100644 index 00000000000..aab99f602d5 --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower-pattern.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_AST_LOWER_PATTERN +#define RUST_AST_LOWER_PATTERN + +#include "rust-ast-lower-base.h" + +namespace Rust { +namespace HIR { + +class ASTLoweringPattern : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::Pattern *translate (AST::Pattern *pattern) + { + ASTLoweringPattern resolver; + pattern->accept_vis (resolver); + + rust_assert (resolver.translated != nullptr); + + resolver.mappings->insert_hir_pattern (resolver.translated); + resolver.mappings->insert_location ( + resolver.translated->get_pattern_mappings ().get_hirid (), + pattern->get_locus ()); + + return resolver.translated; + } + + void visit (AST::IdentifierPattern &pattern) override; + + void visit (AST::PathInExpression &pattern) override; + + void visit (AST::StructPattern &pattern) override; + + void visit (AST::TupleStructPattern &pattern) override; + + void visit (AST::WildcardPattern &pattern) override; + + void visit (AST::TuplePattern &pattern) override; + + void visit (AST::LiteralPattern &pattern) override; + + void visit (AST::RangePattern &pattern) override; + +private: + ASTLoweringPattern () : translated (nullptr) {} + + HIR::Pattern *translated; +}; + +} // namespace HIR +} // namespace Rust + +#endif // RUST_AST_LOWER_PATTERN diff --git a/gcc/rust/hir/rust-ast-lower-stmt.h b/gcc/rust/hir/rust-ast-lower-stmt.h new file mode 100644 index 00000000000..2b26ae3835c --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower-stmt.h @@ -0,0 +1,418 @@ +// 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_LOWER_STMT +#define RUST_AST_LOWER_STMT + +#include "rust-diagnostics.h" + +#include "rust-ast-lower-base.h" +#include "rust-ast-lower-enumitem.h" +#include "rust-ast-lower-type.h" +#include "rust-ast-lower-block.h" +#include "rust-ast-lower-expr.h" +#include "rust-ast-lower-pattern.h" + +namespace Rust { +namespace HIR { + +class ASTLoweringStmt : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::Stmt *translate (AST::Stmt *stmt, bool *terminated) + { + ASTLoweringStmt resolver; + stmt->accept_vis (resolver); + + rust_assert (resolver.translated != nullptr); + *terminated = resolver.terminated; + resolver.mappings->insert_location ( + resolver.translated->get_mappings ().get_hirid (), + resolver.translated->get_locus ()); + resolver.mappings->insert_hir_stmt (resolver.translated); + if (resolver.translated->is_item ()) + { + HIR::Item *i = static_cast (resolver.translated); + + auto defid = resolver.translated->get_mappings ().get_defid (); + + resolver.handle_outer_attributes (*i); + resolver.mappings->insert_hir_item (i); + resolver.mappings->insert_defid_mapping (defid, i); + } + + return resolver.translated; + } + + void visit (AST::ExprStmtWithBlock &stmt) override + { + HIR::ExprWithBlock *expr + = ASTLoweringExprWithBlock::translate (stmt.get_expr ().get (), + &terminated); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, stmt.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + translated + = new HIR::ExprStmtWithBlock (mapping, + std::unique_ptr (expr), + stmt.get_locus (), + !stmt.is_semicolon_followed ()); + } + + void visit (AST::ExprStmtWithoutBlock &stmt) override + { + HIR::Expr *expr + = ASTLoweringExpr::translate (stmt.get_expr ().get (), &terminated); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, stmt.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + translated + = new HIR::ExprStmtWithoutBlock (mapping, + std::unique_ptr (expr), + stmt.get_locus ()); + } + + void visit (AST::ConstantItem &constant) override + { + HIR::Visibility vis = translate_visibility (constant.get_visibility ()); + + HIR::Type *type = ASTLoweringType::translate (constant.get_type ().get ()); + HIR::Expr *expr = ASTLoweringExpr::translate (constant.get_expr ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, constant.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::ConstantItem (mapping, constant.get_identifier (), + vis, std::unique_ptr (type), + std::unique_ptr (expr), + constant.get_outer_attrs (), + constant.get_locus ()); + } + + void visit (AST::LetStmt &stmt) override + { + HIR::Pattern *variables + = ASTLoweringPattern::translate (stmt.get_pattern ().get ()); + HIR::Type *type = stmt.has_type () + ? ASTLoweringType::translate (stmt.get_type ().get ()) + : nullptr; + HIR::Expr *init_expression + = stmt.has_init_expr () + ? ASTLoweringExpr::translate (stmt.get_init_expr ().get ()) + : nullptr; + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, stmt.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + translated + = new HIR::LetStmt (mapping, std::unique_ptr (variables), + std::unique_ptr (init_expression), + std::unique_ptr (type), + stmt.get_outer_attrs (), stmt.get_locus ()); + } + + void visit (AST::TupleStruct &struct_decl) override + { + std::vector> generic_params; + if (struct_decl.has_generics ()) + { + generic_params + = lower_generic_params (struct_decl.get_generic_params ()); + } + + std::vector> where_clause_items; + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::Visibility vis = translate_visibility (struct_decl.get_visibility ()); + + std::vector fields; + for (AST::TupleField &field : struct_decl.get_fields ()) + { + HIR::Visibility vis = translate_visibility (field.get_visibility ()); + HIR::Type *type + = ASTLoweringType::translate (field.get_field_type ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, field.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id ( + crate_num)); + + HIR::TupleField translated_field (mapping, + std::unique_ptr (type), + vis, field.get_locus (), + field.get_outer_attrs ()); + fields.push_back (std::move (translated_field)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, struct_decl.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::TupleStruct (mapping, std::move (fields), + struct_decl.get_identifier (), + std::move (generic_params), + std::move (where_clause), vis, + struct_decl.get_outer_attrs (), + struct_decl.get_locus ()); + } + + void visit (AST::StructStruct &struct_decl) override + { + std::vector> generic_params; + if (struct_decl.has_generics ()) + { + generic_params + = lower_generic_params (struct_decl.get_generic_params ()); + } + + std::vector> where_clause_items; + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::Visibility vis = translate_visibility (struct_decl.get_visibility ()); + + bool is_unit = struct_decl.is_unit_struct (); + std::vector fields; + for (AST::StructField &field : struct_decl.get_fields ()) + { + HIR::Visibility vis = translate_visibility (field.get_visibility ()); + HIR::Type *type + = ASTLoweringType::translate (field.get_field_type ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, field.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id ( + crate_num)); + + HIR::StructField translated_field (mapping, field.get_field_name (), + std::unique_ptr (type), + vis, field.get_locus (), + field.get_outer_attrs ()); + + if (struct_field_name_exists (fields, translated_field)) + break; + + fields.push_back (std::move (translated_field)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, struct_decl.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::StructStruct (mapping, std::move (fields), + struct_decl.get_identifier (), + std::move (generic_params), + std::move (where_clause), is_unit, vis, + struct_decl.get_outer_attrs (), + struct_decl.get_locus ()); + } + + void visit (AST::Union &union_decl) override + { + std::vector> generic_params; + if (union_decl.has_generics ()) + { + generic_params + = lower_generic_params (union_decl.get_generic_params ()); + } + + std::vector> where_clause_items; + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::Visibility vis = translate_visibility (union_decl.get_visibility ()); + + std::vector variants; + for (AST::StructField &variant : union_decl.get_variants ()) + { + HIR::Visibility vis = translate_visibility (variant.get_visibility ()); + HIR::Type *type + = ASTLoweringType::translate (variant.get_field_type ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, variant.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id ( + crate_num)); + + HIR::StructField translated_variant (mapping, variant.get_field_name (), + std::unique_ptr (type), + vis, variant.get_locus (), + variant.get_outer_attrs ()); + + if (struct_field_name_exists (variants, translated_variant)) + break; + + variants.push_back (std::move (translated_variant)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, union_decl.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated + = new HIR::Union (mapping, union_decl.get_identifier (), vis, + std::move (generic_params), std::move (where_clause), + std::move (variants), union_decl.get_outer_attrs (), + union_decl.get_locus ()); + } + + void visit (AST::Enum &enum_decl) override + { + std::vector> generic_params; + if (enum_decl.has_generics ()) + { + generic_params = lower_generic_params (enum_decl.get_generic_params ()); + } + + std::vector> where_clause_items; + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::Visibility vis = translate_visibility (enum_decl.get_visibility ()); + + // bool is_unit = enum_decl.is_zero_variant (); + std::vector> items; + for (auto &variant : enum_decl.get_variants ()) + { + HIR::EnumItem *hir_item + = ASTLoweringEnumItem::translate (variant.get ()); + items.push_back (std::unique_ptr (hir_item)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, enum_decl.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::Enum (mapping, enum_decl.get_identifier (), vis, + std::move (generic_params), + std::move (where_clause), /* is_unit, */ + std::move (items), enum_decl.get_outer_attrs (), + enum_decl.get_locus ()); + } + + void visit (AST::EmptyStmt &empty) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, empty.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::EmptyStmt (mapping, empty.get_locus ()); + } + + void visit (AST::Function &function) override + { + // ignore for now and leave empty + std::vector> where_clause_items; + HIR::WhereClause where_clause (std::move (where_clause_items)); + HIR::FunctionQualifiers qualifiers + = lower_qualifiers (function.get_qualifiers ()); + HIR::Visibility vis = translate_visibility (function.get_visibility ()); + + // need + std::vector> generic_params; + if (function.has_generics ()) + { + generic_params = lower_generic_params (function.get_generic_params ()); + } + + Identifier function_name = function.get_function_name (); + Location locus = function.get_locus (); + + std::unique_ptr return_type + = function.has_return_type () ? std::unique_ptr ( + ASTLoweringType::translate (function.get_return_type ().get ())) + : nullptr; + + std::vector function_params; + for (auto ¶m : function.get_function_params ()) + { + auto translated_pattern = std::unique_ptr ( + ASTLoweringPattern::translate (param.get_pattern ().get ())); + auto translated_type = std::unique_ptr ( + ASTLoweringType::translate (param.get_type ().get ())); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, param.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + auto hir_param + = HIR::FunctionParam (mapping, std::move (translated_pattern), + std::move (translated_type), + param.get_locus ()); + function_params.push_back (hir_param); + } + + bool terminated = false; + std::unique_ptr function_body + = std::unique_ptr ( + ASTLoweringBlock::translate (function.get_definition ().get (), + &terminated)); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, function.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + mappings->insert_location (function_body->get_mappings ().get_hirid (), + function.get_locus ()); + + auto fn + = new HIR::Function (mapping, std::move (function_name), + std::move (qualifiers), std::move (generic_params), + std::move (function_params), std::move (return_type), + std::move (where_clause), std::move (function_body), + std::move (vis), function.get_outer_attrs (), + HIR::SelfParam::error (), locus); + + // add the mappings for the function params at the end + for (auto ¶m : fn->get_function_params ()) + { + mappings->insert_hir_param (¶m); + mappings->insert_location (mapping.get_hirid (), param.get_locus ()); + } + + translated = fn; + } + + void visit (AST::ExternBlock &extern_block) override + { + translated = lower_extern_block (extern_block); + } + +private: + ASTLoweringStmt () : translated (nullptr), terminated (false) {} + + HIR::Stmt *translated; + bool terminated; +}; + +} // namespace HIR +} // namespace Rust + +#endif // RUST_AST_LOWER_PATTERN diff --git a/gcc/rust/hir/rust-ast-lower-struct-field-expr.h b/gcc/rust/hir/rust-ast-lower-struct-field-expr.h new file mode 100644 index 00000000000..dadf3594904 --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower-struct-field-expr.h @@ -0,0 +1,63 @@ +// 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_LOWER_STRUCT_FIELD_EXPR +#define RUST_AST_LOWER_STRUCT_FIELD_EXPR + +#include "rust-diagnostics.h" +#include "rust-ast-lower-base.h" + +namespace Rust { +namespace HIR { + +class ASTLowerStructExprField : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::StructExprField *translate (AST::StructExprField *field) + { + ASTLowerStructExprField compiler; + field->accept_vis (compiler); + rust_assert (compiler.translated != nullptr); + + compiler.mappings->insert_hir_struct_field (compiler.translated); + compiler.mappings->insert_location ( + compiler.translated->get_mappings ().get_hirid (), field->get_locus ()); + + return compiler.translated; + } + + ~ASTLowerStructExprField () {} + + void visit (AST::StructExprFieldIdentifierValue &field) override; + + void visit (AST::StructExprFieldIndexValue &field) override; + + void visit (AST::StructExprFieldIdentifier &field) override; + +private: + ASTLowerStructExprField () : translated (nullptr) {} + + HIR::StructExprField *translated; +}; + +} // namespace HIR +} // namespace Rust + +#endif // RUST_AST_LOWER_STRUCT_FIELD_EXPR diff --git a/gcc/rust/hir/rust-ast-lower-type.h b/gcc/rust/hir/rust-ast-lower-type.h new file mode 100644 index 00000000000..46f765a3ea2 --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower-type.h @@ -0,0 +1,532 @@ +// 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_LOWER_TYPE +#define RUST_AST_LOWER_TYPE + +#include "rust-ast-lower-base.h" +#include "rust-diagnostics.h" +#include "rust-ast-lower-expr.h" + +namespace Rust { +namespace HIR { + +class ASTLowerTypePath : public ASTLoweringBase +{ +protected: + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::TypePath *translate (AST::TypePath &type) + { + ASTLowerTypePath resolver; + type.accept_vis (resolver); + rust_assert (resolver.translated != nullptr); + return resolver.translated; + } + + void visit (AST::TypePathSegmentFunction &) override { gcc_unreachable (); } + + void visit (AST::TypePathSegment &segment) override + { + auto crate_num = mappings->get_current_crate (); + auto hirid = mappings->get_next_hir_id (crate_num); + Analysis::NodeMapping mapping (crate_num, segment.get_node_id (), hirid, + UNKNOWN_LOCAL_DEFID); + + HIR::PathIdentSegment ident (segment.get_ident_segment ().as_string ()); + translated_segment + = new HIR::TypePathSegment (std::move (mapping), ident, + segment.get_separating_scope_resolution (), + segment.get_locus ()); + } + + void visit (AST::TypePathSegmentGeneric &segment) override; + + void visit (AST::TypePath &path) override + { + std::vector> translated_segments; + + for (auto &seg : path.get_segments ()) + { + translated_segment = nullptr; + seg->accept_vis (*this); + if (translated_segment == nullptr) + { + rust_fatal_error (seg->get_locus (), + "failed to translate AST TypePathSegment"); + } + translated_segments.push_back ( + std::unique_ptr (translated_segment)); + } + + auto crate_num = mappings->get_current_crate (); + auto hirid = mappings->get_next_hir_id (crate_num); + Analysis::NodeMapping mapping (crate_num, path.get_node_id (), hirid, + mappings->get_next_localdef_id (crate_num)); + + translated + = new HIR::TypePath (std::move (mapping), std::move (translated_segments), + path.get_locus (), + path.has_opening_scope_resolution_op ()); + } + +protected: + HIR::TypePathSegment *translated_segment; + +private: + HIR::TypePath *translated; +}; + +class ASTLowerQualifiedPathInType : public ASTLowerTypePath +{ + using ASTLowerTypePath::visit; + +public: + static HIR::QualifiedPathInType *translate (AST::QualifiedPathInType &type) + { + ASTLowerQualifiedPathInType resolver; + type.accept_vis (resolver); + rust_assert (resolver.translated != nullptr); + return resolver.translated; + } + + void visit (AST::QualifiedPathInType &path) override; + +private: + HIR::QualifiedPathInType *translated; +}; + +class ASTLoweringType : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::Type *translate (AST::Type *type) + { + ASTLoweringType resolver; + type->accept_vis (resolver); + + rust_assert (resolver.translated != nullptr); + resolver.mappings->insert_hir_type (resolver.translated); + resolver.mappings->insert_location ( + resolver.translated->get_mappings ().get_hirid (), + resolver.translated->get_locus ()); + + return resolver.translated; + } + + void visit (AST::BareFunctionType &fntype) override + { + bool is_variadic = false; + std::vector lifetime_params; + HIR::FunctionQualifiers qualifiers + = lower_qualifiers (fntype.get_function_qualifiers ()); + + std::vector named_params; + for (auto ¶m : fntype.get_function_params ()) + { + HIR::MaybeNamedParam::ParamKind kind; + switch (param.get_param_kind ()) + { + case AST::MaybeNamedParam::ParamKind::UNNAMED: + kind = HIR::MaybeNamedParam::ParamKind::UNNAMED; + break; + case AST::MaybeNamedParam::ParamKind::IDENTIFIER: + kind = HIR::MaybeNamedParam::ParamKind::IDENTIFIER; + break; + case AST::MaybeNamedParam::ParamKind::WILDCARD: + kind = HIR::MaybeNamedParam::ParamKind::WILDCARD; + break; + default: + gcc_unreachable (); + } + + HIR::Type *param_type + = ASTLoweringType::translate (param.get_type ().get ()); + + HIR::MaybeNamedParam p (param.get_name (), kind, + std::unique_ptr (param_type), + param.get_locus ()); + named_params.push_back (std::move (p)); + } + + HIR::Type *return_type = nullptr; + if (fntype.has_return_type ()) + { + return_type + = ASTLoweringType::translate (fntype.get_return_type ().get ()); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, fntype.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::BareFunctionType ( + std::move (mapping), std::move (lifetime_params), std::move (qualifiers), + std::move (named_params), is_variadic, + std::unique_ptr (return_type), fntype.get_locus ()); + } + + void visit (AST::TupleType &tuple) override + { + std::vector> elems; + for (auto &e : tuple.get_elems ()) + { + HIR::Type *t = ASTLoweringType::translate (e.get ()); + elems.push_back (std::unique_ptr (t)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, tuple.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::TupleType (std::move (mapping), std::move (elems), + tuple.get_locus ()); + } + + void visit (AST::TypePath &path) override + { + translated = ASTLowerTypePath::translate (path); + } + + void visit (AST::QualifiedPathInType &path) override + { + translated = ASTLowerQualifiedPathInType::translate (path); + } + + void visit (AST::ArrayType &type) override + { + HIR::Type *translated_type + = ASTLoweringType::translate (type.get_elem_type ().get ()); + HIR::Expr *array_size + = ASTLoweringExpr::translate (type.get_size_expr ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, type.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated + = new HIR::ArrayType (mapping, + std::unique_ptr (translated_type), + std::unique_ptr (array_size), + type.get_locus ()); + } + + void visit (AST::ReferenceType &type) override + { + HIR::Lifetime lifetime = lower_lifetime (type.get_lifetime ()); + + HIR::Type *base_type + = ASTLoweringType::translate (type.get_base_type ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, type.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::ReferenceType (mapping, + type.get_has_mut () ? Mutability::Mut + : Mutability::Imm, + std::unique_ptr (base_type), + type.get_locus (), lifetime); + } + + void visit (AST::RawPointerType &type) override + { + HIR::Type *base_type + = ASTLoweringType::translate (type.get_type_pointed_to ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, type.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated + = new HIR::RawPointerType (mapping, + type.get_pointer_type () + == AST::RawPointerType::PointerType::MUT + ? Mutability::Mut + : Mutability::Imm, + std::unique_ptr (base_type), + type.get_locus ()); + } + + void visit (AST::SliceType &type) override + { + HIR::Type *base_type + = ASTLoweringType::translate (type.get_elem_type ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, type.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated + = new HIR::SliceType (mapping, std::unique_ptr (base_type), + type.get_locus ()); + } + + void visit (AST::InferredType &type) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, type.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::InferredType (mapping, type.get_locus ()); + } + + void visit (AST::NeverType &type) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, type.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::NeverType (mapping, type.get_locus ()); + } + + void visit (AST::TraitObjectTypeOneBound &type) override; + + void visit (AST::TraitObjectType &type) override; + +private: + ASTLoweringType () : ASTLoweringBase (), translated (nullptr) {} + + HIR::Type *translated; +}; + +class ASTLowerGenericParam : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::GenericParam *translate (AST::GenericParam *param) + { + ASTLowerGenericParam resolver; + param->accept_vis (resolver); + + rust_assert (resolver.translated != nullptr); + resolver.mappings->insert_location ( + resolver.translated->get_mappings ().get_hirid (), param->get_locus ()); + resolver.mappings->insert_hir_generic_param (resolver.translated); + + return resolver.translated; + } + + void visit (AST::LifetimeParam ¶m) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, param.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + HIR::Lifetime lt (mapping, param.get_lifetime ().get_lifetime_type (), + param.get_lifetime ().get_lifetime_name (), + param.get_lifetime ().get_locus ()); + + translated = new HIR::LifetimeParam (mapping, lt, param.get_locus (), + std::vector ()); + } + + void visit (AST::ConstGenericParam ¶m) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, param.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + auto type = ASTLoweringType::translate (param.get_type ().get ()); + + HIR::Expr *default_expr = nullptr; + if (param.has_default_value ()) + default_expr = ASTLoweringExpr::translate ( + param.get_default_value ().get_expression ().get ()); + + translated + = new HIR::ConstGenericParam (param.get_name (), + std::unique_ptr (type), + std::unique_ptr (default_expr), + mapping, param.get_locus ()); + } + + void visit (AST::TypeParam ¶m) override + { + AST::Attribute outer_attr = AST::Attribute::create_empty (); + std::vector> type_param_bounds; + if (param.has_type_param_bounds ()) + { + for (auto &bound : param.get_type_param_bounds ()) + { + HIR::TypeParamBound *lowered_bound = lower_bound (bound.get ()); + type_param_bounds.push_back ( + std::unique_ptr (lowered_bound)); + } + } + + HIR::Type *type = param.has_type () + ? ASTLoweringType::translate (param.get_type ().get ()) + : nullptr; + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, param.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated + = new HIR::TypeParam (mapping, param.get_type_representation (), + param.get_locus (), std::move (type_param_bounds), + std::unique_ptr (type), + std::move (outer_attr)); + } + +private: + ASTLowerGenericParam () : ASTLoweringBase (), translated (nullptr) {} + + HIR::GenericParam *translated; +}; + +class ASTLoweringTypeBounds : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::TypeParamBound *translate (AST::TypeParamBound *type) + { + ASTLoweringTypeBounds resolver; + type->accept_vis (resolver); + + rust_assert (resolver.translated != nullptr); + resolver.mappings->insert_location ( + resolver.translated->get_mappings ().get_hirid (), + resolver.translated->get_locus ()); + + return resolver.translated; + } + + void visit (AST::TraitBound &bound) override + { + // FIXME + std::vector lifetimes; + + AST::TypePath &ast_trait_path = bound.get_type_path (); + HIR::TypePath *trait_path = ASTLowerTypePath::translate (ast_trait_path); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, bound.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::TraitBound (mapping, *trait_path, bound.get_locus (), + bound.is_in_parens (), + bound.has_opening_question_mark ()); + } + + void visit (AST::Lifetime &bound) override + { + HIR::Lifetime lifetime = lower_lifetime (bound); + translated = new HIR::Lifetime (lifetime); + } + +private: + ASTLoweringTypeBounds () : ASTLoweringBase (), translated (nullptr) {} + + HIR::TypeParamBound *translated; +}; + +class ASTLowerWhereClauseItem : public ASTLoweringBase +{ + using Rust::HIR::ASTLoweringBase::visit; + +public: + static HIR::WhereClauseItem *translate (AST::WhereClauseItem &item) + { + ASTLowerWhereClauseItem compiler; + item.accept_vis (compiler); + + rust_assert (compiler.translated != nullptr); + // FIXME + // compiler.mappings->insert_location ( + // compiler.translated->get_mappings ().get_hirid (), + // compiler.translated->get_locus ()); + + return compiler.translated; + } + + void visit (AST::LifetimeWhereClauseItem &item) override + { + HIR::Lifetime l = lower_lifetime (item.get_lifetime ()); + std::vector lifetime_bounds; + for (auto &lifetime_bound : item.get_lifetime_bounds ()) + { + HIR::Lifetime ll = lower_lifetime (lifetime_bound); + lifetime_bounds.push_back (std::move (ll)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, item.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::LifetimeWhereClauseItem (mapping, std::move (l), + std::move (lifetime_bounds), + item.get_locus ()); + } + + void visit (AST::TypeBoundWhereClauseItem &item) override + { + // FIXME + std::vector for_lifetimes; + + std::unique_ptr bound_type = std::unique_ptr ( + ASTLoweringType::translate (item.get_type ().get ())); + + std::vector> type_param_bounds; + for (auto &bound : item.get_type_param_bounds ()) + { + HIR::TypeParamBound *b + = ASTLoweringTypeBounds::translate (bound.get ()); + type_param_bounds.push_back (std::unique_ptr (b)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, item.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::TypeBoundWhereClauseItem (mapping, std::move (for_lifetimes), + std::move (bound_type), + std::move (type_param_bounds), + item.get_locus ()); + } + +private: + ASTLowerWhereClauseItem () : ASTLoweringBase (), translated (nullptr) {} + + HIR::WhereClauseItem *translated; +}; + +} // namespace HIR +} // namespace Rust + +#endif // RUST_AST_LOWER_TYPE diff --git a/gcc/rust/hir/rust-ast-lower.cc b/gcc/rust/hir/rust-ast-lower.cc new file mode 100644 index 00000000000..0bec8b088af --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower.cc @@ -0,0 +1,477 @@ +// 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 +// . + +#include "rust-ast-lower.h" +#include "rust-ast-lower-item.h" +#include "rust-ast-lower-implitem.h" +#include "rust-ast-lower-expr.h" +#include "rust-ast-lower-block.h" +#include "rust-ast-lower-type.h" + +namespace Rust { +namespace HIR { + +Visibility +translate_visibility (const AST::Visibility &vis) +{ + // FIXME: How do we create a private visibility here? Is it always private if + // the AST vis is an error? + // FIXME: We need to add a `create_private()` static function to the + // AST::Visibility class and use it when the vis is empty in the parser... + if (vis.is_error ()) + return Visibility::create_error (); + + switch (vis.get_public_vis_type ()) + { + case AST::Visibility::PUB: + return Visibility (Visibility::VisType::PUBLIC); + case AST::Visibility::PRIV: + case AST::Visibility::PUB_SELF: + return Visibility (Visibility::VisType::PRIVATE); + case AST::Visibility::PUB_CRATE: + case AST::Visibility::PUB_SUPER: + case AST::Visibility::PUB_IN_PATH: + return Visibility (Visibility::VisType::RESTRICTED, + ASTLoweringSimplePath::translate (vis.get_path ())); + break; + } + + return Visibility::create_error (); +} + +ASTLowering::ASTLowering (AST::Crate &astCrate) : astCrate (astCrate) {} + +ASTLowering::~ASTLowering () {} + +std::unique_ptr +ASTLowering::Resolve (AST::Crate &astCrate) +{ + ASTLowering resolver (astCrate); + return resolver.go (); +} + +std::unique_ptr +ASTLowering::go () +{ + std::vector > items; + + for (auto it = astCrate.items.begin (); it != astCrate.items.end (); it++) + { + auto translated = ASTLoweringItem::translate (it->get ()); + if (translated != nullptr) + items.push_back (std::unique_ptr (translated)); + } + + auto mappings = Analysis::Mappings::get (); + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, astCrate.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + return std::unique_ptr ( + new HIR::Crate (std::move (items), astCrate.get_inner_attrs (), mapping)); +} + +// rust-ast-lower-block.h +void +ASTLoweringBlock::visit (AST::BlockExpr &expr) +{ + std::vector > block_stmts; + bool block_did_terminate = false; + + for (auto &s : expr.get_statements ()) + { + if (s->get_ast_kind () == AST::Kind::MACRO_RULES_DEFINITION) + continue; + + if (s->get_ast_kind () == AST::Kind::MACRO_INVOCATION) + rust_fatal_error ( + s->get_locus (), + "macro invocations should not get lowered to HIR - At " + "this point in " + "the pipeline, they should all have been expanded"); + + if (block_did_terminate) + rust_warning_at (s->get_locus (), 0, "unreachable statement"); + + bool terminated = false; + auto translated_stmt = ASTLoweringStmt::translate (s.get (), &terminated); + block_stmts.push_back (std::unique_ptr (translated_stmt)); + block_did_terminate |= terminated; + } + + if (expr.has_tail_expr () && block_did_terminate) + { + // warning unreachable tail expressions + rust_warning_at (expr.get_tail_expr ()->get_locus (), 0, + "unreachable expression"); + } + + HIR::ExprWithoutBlock *tail_expr = nullptr; + if (expr.has_tail_expr ()) + { + bool terminated = false; + tail_expr = (HIR::ExprWithoutBlock *) + ASTLoweringExpr::translate (expr.get_tail_expr ().get (), &terminated); + block_did_terminate |= terminated; + } + + bool tail_reachable = !block_did_terminate; + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + translated + = new HIR::BlockExpr (mapping, std::move (block_stmts), + std::unique_ptr (tail_expr), + tail_reachable, expr.get_inner_attrs (), + expr.get_outer_attrs (), expr.get_start_locus (), + expr.get_end_locus ()); + + terminated = block_did_terminate; +} + +void +ASTLoweringIfBlock::visit (AST::IfExpr &expr) +{ + bool ignored_terminated = false; + HIR::Expr *condition + = ASTLoweringExpr::translate (expr.get_condition_expr ().get (), + &ignored_terminated); + HIR::BlockExpr *block + = ASTLoweringBlock::translate (expr.get_if_block ().get (), + &ignored_terminated); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::IfExpr (mapping, std::unique_ptr (condition), + std::unique_ptr (block), + expr.get_locus ()); +} + +void +ASTLoweringIfBlock::visit (AST::IfExprConseqElse &expr) +{ + HIR::Expr *condition + = ASTLoweringExpr::translate (expr.get_condition_expr ().get ()); + + bool if_block_terminated = false; + bool else_block_termianted = false; + + HIR::BlockExpr *if_block + = ASTLoweringBlock::translate (expr.get_if_block ().get (), + &if_block_terminated); + HIR::BlockExpr *else_block + = ASTLoweringBlock::translate (expr.get_else_block ().get (), + &else_block_termianted); + + terminated = if_block_terminated && else_block_termianted; + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::IfExprConseqElse (mapping, + std::unique_ptr (condition), + std::unique_ptr (if_block), + std::unique_ptr (else_block), + expr.get_locus ()); +} + +void +ASTLoweringIfBlock::visit (AST::IfExprConseqIf &expr) +{ + HIR::Expr *condition + = ASTLoweringExpr::translate (expr.get_condition_expr ().get ()); + + bool ignored_terminated = false; + HIR::BlockExpr *block + = ASTLoweringBlock::translate (expr.get_if_block ().get (), + &ignored_terminated); + HIR::IfExpr *conseq_if_expr + = ASTLoweringIfBlock::translate (expr.get_conseq_if_expr ().get (), + &ignored_terminated); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::IfExprConseqIf (mapping, std::unique_ptr (condition), + std::unique_ptr (block), + std::unique_ptr (conseq_if_expr), + expr.get_locus ()); +} + +void +ASTLoweringIfLetBlock::visit (AST::IfLetExpr &expr) +{ + std::vector > patterns; + for (auto &pattern : expr.get_patterns ()) + { + HIR::Pattern *ptrn = ASTLoweringPattern::translate (pattern.get ()); + patterns.push_back (std::unique_ptr (ptrn)); + } + HIR::Expr *value_ptr + = ASTLoweringExpr::translate (expr.get_value_expr ().get ()); + + bool ignored_terminated = false; + HIR::BlockExpr *block + = ASTLoweringBlock::translate (expr.get_if_block ().get (), + &ignored_terminated); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::IfLetExpr (mapping, std::move (patterns), + std::unique_ptr (value_ptr), + std::unique_ptr (block), + expr.get_locus ()); +} + +// rust-ast-lower-struct-field-expr.h + +void +ASTLowerStructExprField::visit (AST::StructExprFieldIdentifierValue &field) +{ + HIR::Expr *value = ASTLoweringExpr::translate (field.get_value ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, field.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::StructExprFieldIdentifierValue ( + mapping, field.get_field_name (), std::unique_ptr (value), + field.get_locus ()); +} + +void +ASTLowerStructExprField::visit (AST::StructExprFieldIndexValue &field) +{ + HIR::Expr *value = ASTLoweringExpr::translate (field.get_value ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, field.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::StructExprFieldIndexValue (mapping, field.get_index (), + std::unique_ptr (value), + field.get_locus ()); +} + +void +ASTLowerStructExprField::visit (AST::StructExprFieldIdentifier &field) +{ + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, field.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::StructExprFieldIdentifier (mapping, field.get_field_name (), + field.get_locus ()); +} + +// rust-ast-lower-block.h + +void +ASTLoweringExprWithBlock::visit (AST::WhileLoopExpr &expr) +{ + HIR::BlockExpr *loop_block + = ASTLoweringBlock::translate (expr.get_loop_block ().get (), &terminated); + + HIR::LoopLabel loop_label = lower_loop_label (expr.get_loop_label ()); + HIR::Expr *loop_condition + = ASTLoweringExpr::translate (expr.get_predicate_expr ().get (), + &terminated); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::WhileLoopExpr (mapping, + std::unique_ptr (loop_condition), + std::unique_ptr (loop_block), + expr.get_locus (), std::move (loop_label), + expr.get_outer_attrs ()); +} + +void +ASTLoweringExprWithBlock::visit (AST::ForLoopExpr &expr) +{ + HIR::BlockExpr *loop_block + = ASTLoweringBlock::translate (expr.get_loop_block ().get (), &terminated); + HIR::LoopLabel loop_label = lower_loop_label (expr.get_loop_label ()); + HIR::Expr *iterator_expr + = ASTLoweringExpr::translate (expr.get_iterator_expr ().get (), + &terminated); + HIR::Pattern *loop_pattern + = ASTLoweringPattern::translate (expr.get_pattern ().get ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::ForLoopExpr (mapping, + std::unique_ptr (loop_pattern), + std::unique_ptr (iterator_expr), + std::unique_ptr (loop_block), + expr.get_locus (), std::move (loop_label), + expr.get_outer_attrs ()); +} + +void +ASTLoweringExprWithBlock::visit (AST::MatchExpr &expr) +{ + HIR::Expr *branch_value + = ASTLoweringExpr::translate (expr.get_scrutinee_expr ().get ()); + + std::vector match_arms; + for (auto &match_case : expr.get_match_cases ()) + { + HIR::Expr *kase_expr + = ASTLoweringExpr::translate (match_case.get_expr ().get ()); + + HIR::Expr *kase_guard_expr = nullptr; + if (match_case.get_arm ().has_match_arm_guard ()) + { + kase_guard_expr = ASTLoweringExpr::translate ( + match_case.get_arm ().get_guard_expr ().get ()); + } + + std::vector > match_arm_patterns; + for (auto &pattern : match_case.get_arm ().get_patterns ()) + { + HIR::Pattern *ptrn = ASTLoweringPattern::translate (pattern.get ()); + match_arm_patterns.push_back (std::unique_ptr (ptrn)); + } + + HIR::MatchArm arm (std::move (match_arm_patterns), expr.get_locus (), + std::unique_ptr (kase_guard_expr), + match_case.get_arm ().get_outer_attrs ()); + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + HIR::MatchCase kase (std::move (mapping), std::move (arm), + std::unique_ptr (kase_expr)); + match_arms.push_back (std::move (kase)); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated + = new HIR::MatchExpr (mapping, std::unique_ptr (branch_value), + std::move (match_arms), expr.get_inner_attrs (), + expr.get_outer_attrs (), expr.get_locus ()); +} + +// rust-ast-lower-expr.h + +void +ASTLowerPathInExpression::visit (AST::PathInExpression &expr) +{ + std::vector path_segments; + auto &segments = expr.get_segments (); + for (auto &s : segments) + { + path_segments.push_back (lower_path_expr_seg ((s))); + + // insert the mappings for the segment + HIR::PathExprSegment *lowered_seg = &path_segments.back (); + mappings->insert_hir_path_expr_seg (lowered_seg); + } + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::PathInExpression (mapping, std::move (path_segments), + expr.get_locus (), + expr.opening_scope_resolution ()); +} + +HIR::QualifiedPathType +ASTLoweringBase::lower_qual_path_type (AST::QualifiedPathType &qualified_type) +{ + HIR::Type *type + = ASTLoweringType::translate (qualified_type.get_type ().get ()); + HIR::TypePath *trait + = qualified_type.has_as_clause () + ? ASTLowerTypePath::translate (qualified_type.get_as_type_path ()) + : nullptr; + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, qualified_type.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + return HIR::QualifiedPathType (mapping, std::unique_ptr (type), + std::unique_ptr (trait), + qualified_type.get_locus ()); +} + +void +ASTLowerQualPathInExpression::visit (AST::QualifiedPathInExpression &expr) +{ + HIR::QualifiedPathType qual_path_type + = lower_qual_path_type (expr.get_qualified_path_type ()); + + std::vector path_segments; + auto &segments = expr.get_segments (); + for (auto &s : segments) + { + path_segments.push_back (lower_path_expr_seg ((s))); + + // insert the mappings for the segment + HIR::PathExprSegment *lowered_seg = &path_segments.back (); + mappings->insert_hir_path_expr_seg (lowered_seg); + } + + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, expr.get_node_id (), + mappings->get_next_hir_id (crate_num), + UNKNOWN_LOCAL_DEFID); + + translated = new HIR::QualifiedPathInExpression (mapping, qual_path_type, + std::move (path_segments), + expr.get_locus (), + expr.get_outer_attrs ()); +} +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/hir/rust-ast-lower.h b/gcc/rust/hir/rust-ast-lower.h new file mode 100644 index 00000000000..e726b4b8282 --- /dev/null +++ b/gcc/rust/hir/rust-ast-lower.h @@ -0,0 +1,59 @@ +// 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_HIR_LOWER +#define RUST_HIR_LOWER + +#include "rust-system.h" +#include "rust-ast-full.h" +#include "rust-ast-visitor.h" +#include "rust-hir-full.h" + +namespace Rust { +namespace HIR { + +/* Checks whether the name of a field already exists. Returns true + and produces an error if so. */ +bool +struct_field_name_exists (std::vector &fields, + HIR::StructField &new_field); + +/** + * Lowers a Visibility from the AST into an HIR Visibility, desugaring it in + * the process + */ +Visibility +translate_visibility (const AST::Visibility &vis); + +class ASTLowering +{ +public: + static std::unique_ptr Resolve (AST::Crate &astCrate); + ~ASTLowering (); + +private: + ASTLowering (AST::Crate &astCrate); + std::unique_ptr go (); + + AST::Crate &astCrate; +}; + +} // namespace HIR +} // namespace Rust + +#endif // RUST_HIR_LOWER diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc new file mode 100644 index 00000000000..bb139a7c1b7 --- /dev/null +++ b/gcc/rust/hir/rust-hir-dump.cc @@ -0,0 +1,521 @@ +// 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 +// . + +#include "rust-hir-dump.h" + +namespace Rust { +namespace HIR { + +Dump::Dump (std::ostream &stream) : stream (stream), indent (0) {} + +void +Dump::go (HIR::Crate &crate) +{ + stream << "Crate" + << " " + << "{" << std::endl; + // + + indent++; + stream << std::string (indent, indent_char); + stream << "inner_attrs" + << ":" + << " " + << "["; + for (auto &attr : crate.inner_attrs) + stream << attr.as_string (); + stream << "]" + << "," << std::endl; + indent--; + + indent++; + stream << std::string (indent, indent_char); + // + + stream << "items" + << ":" + << " " + << "["; + + stream << std::string (indent, indent_char); + for (const auto &item : crate.items) + { + stream << std::endl; + item->accept_vis (*this); + } + stream << std::string (indent, indent_char); + stream << "]" + << "," << std::endl; + indent--; + // + + indent++; + stream << std::string (indent, indent_char); + stream << "node_mappings" + << ":" + << " " + << "["; + // TODO: print crate mapping attrs + stream << "]" << std::endl; + indent--; + + stream << "}" << std::endl; +} + +void +Dump::visit (Lifetime &) +{} +void +Dump::visit (LifetimeParam &) +{} +void +Dump::visit (PathInExpression &) +{} +void +Dump::visit (TypePathSegment &) +{} +void +Dump::visit (TypePathSegmentGeneric &) +{} +void +Dump::visit (TypePathSegmentFunction &) +{} +void +Dump::visit (TypePath &) +{} +void +Dump::visit (QualifiedPathInExpression &) +{} +void +Dump::visit (QualifiedPathInType &) +{} + +void +Dump::visit (LiteralExpr &literal_expr) +{ + indent++; + stream << std::string (indent, indent_char); + stream << "( " + literal_expr.get_literal ().as_string () + " (" + + literal_expr.get_mappings ().as_string () + "))"; + stream << "\n"; +} +void +Dump::visit (BorrowExpr &) +{} +void +Dump::visit (DereferenceExpr &) +{} +void +Dump::visit (ErrorPropagationExpr &) +{} +void +Dump::visit (NegationExpr &) +{} +void +Dump::visit (ArithmeticOrLogicalExpr &) +{} +void +Dump::visit (ComparisonExpr &) +{} +void +Dump::visit (LazyBooleanExpr &) +{} +void +Dump::visit (TypeCastExpr &) +{} +void +Dump::visit (AssignmentExpr &) +{} +void +Dump::visit (CompoundAssignmentExpr &) +{} +void +Dump::visit (GroupedExpr &) +{} + +void +Dump::visit (ArrayElemsValues &) +{} +void +Dump::visit (ArrayElemsCopied &) +{} +void +Dump::visit (ArrayExpr &) +{} +void +Dump::visit (ArrayIndexExpr &) +{} +void +Dump::visit (TupleExpr &) +{} +void +Dump::visit (TupleIndexExpr &) +{} +void +Dump::visit (StructExprStruct &) +{} + +void +Dump::visit (StructExprFieldIdentifier &) +{} +void +Dump::visit (StructExprFieldIdentifierValue &) +{} + +void +Dump::visit (StructExprFieldIndexValue &) +{} +void +Dump::visit (StructExprStructFields &) +{} +void +Dump::visit (StructExprStructBase &) +{} + +void +Dump::visit (CallExpr &) +{} +void +Dump::visit (MethodCallExpr &) +{} +void +Dump::visit (FieldAccessExpr &) +{} +void +Dump::visit (ClosureExprInner &) +{} +void +Dump::visit (BlockExpr &block_expr) +{ + stream << "BlockExpr" + << ":" + << " " + << "["; + indent++; + // TODO: print statements + // TODO: print tail expression if exists + stream << "]"; + indent--; +} +void +Dump::visit (ClosureExprInnerTyped &) +{} +void +Dump::visit (ContinueExpr &) +{} +void +Dump::visit (BreakExpr &) +{} +void +Dump::visit (RangeFromToExpr &) +{} +void +Dump::visit (RangeFromExpr &) +{} +void +Dump::visit (RangeToExpr &) +{} +void +Dump::visit (RangeFullExpr &) +{} +void +Dump::visit (RangeFromToInclExpr &) +{} +void +Dump::visit (RangeToInclExpr &) +{} +void +Dump::visit (ReturnExpr &) +{} +void +Dump::visit (UnsafeBlockExpr &) +{} +void +Dump::visit (LoopExpr &) +{} +void +Dump::visit (WhileLoopExpr &) +{} +void +Dump::visit (WhileLetLoopExpr &) +{} +void +Dump::visit (ForLoopExpr &) +{} +void +Dump::visit (IfExpr &) +{} +void +Dump::visit (IfExprConseqElse &) +{} +void +Dump::visit (IfExprConseqIf &) +{} +void +Dump::visit (IfExprConseqIfLet &) +{} +void +Dump::visit (IfLetExpr &) +{} +void +Dump::visit (IfLetExprConseqElse &) +{} +void +Dump::visit (IfLetExprConseqIf &) +{} +void +Dump::visit (IfLetExprConseqIfLet &) +{} + +void +Dump::visit (MatchExpr &) +{} +void +Dump::visit (AwaitExpr &) +{} +void +Dump::visit (AsyncBlockExpr &) +{} + +void +Dump::visit (TypeParam &) +{} + +void +Dump::visit (ConstGenericParam &) +{} + +void +Dump::visit (LifetimeWhereClauseItem &) +{} +void +Dump::visit (TypeBoundWhereClauseItem &) +{} +void +Dump::visit (Module &) +{} +void +Dump::visit (ExternCrate &) +{} + +void +Dump::visit (UseTreeGlob &) +{} +void +Dump::visit (UseTreeList &) +{} +void +Dump::visit (UseTreeRebind &) +{} +void +Dump::visit (UseDeclaration &) +{} +void +Dump::visit (Function &function) +{ + indent++; + stream << std::string (indent, indent_char); + stream << "Function" + << " "; + stream << "{" << std::endl; + // TODO: print function params + stream << std::string (indent, indent_char); + stream << "}" << std::endl; + // TODO: get function definition and visit block + + stream << std::endl; + indent--; +} +void +Dump::visit (TypeAlias &) +{} +void +Dump::visit (StructStruct &) +{} +void +Dump::visit (TupleStruct &) +{} +void +Dump::visit (EnumItem &) +{} +void +Dump::visit (EnumItemTuple &) +{} +void +Dump::visit (EnumItemStruct &) +{} +void +Dump::visit (EnumItemDiscriminant &) +{} +void +Dump::visit (Enum &) +{} +void +Dump::visit (Union &) +{} +void +Dump::visit (ConstantItem &) +{} +void +Dump::visit (StaticItem &) +{} +void +Dump::visit (TraitItemFunc &) +{} +void +Dump::visit (TraitItemConst &) +{} +void +Dump::visit (TraitItemType &) +{} +void +Dump::visit (Trait &) +{} +void +Dump::visit (ImplBlock &) +{} + +void +Dump::visit (ExternalStaticItem &) +{} +void +Dump::visit (ExternalFunctionItem &) +{} +void +Dump::visit (ExternBlock &) +{} + +void +Dump::visit (LiteralPattern &) +{} +void +Dump::visit (IdentifierPattern &) +{} +void +Dump::visit (WildcardPattern &) +{} + +void +Dump::visit (RangePatternBoundLiteral &) +{} +void +Dump::visit (RangePatternBoundPath &) +{} +void +Dump::visit (RangePatternBoundQualPath &) +{} +void +Dump::visit (RangePattern &) +{} +void +Dump::visit (ReferencePattern &) +{} + +void +Dump::visit (StructPatternFieldTuplePat &) +{} +void +Dump::visit (StructPatternFieldIdentPat &) +{} +void +Dump::visit (StructPatternFieldIdent &) +{} +void +Dump::visit (StructPattern &) +{} + +void +Dump::visit (TupleStructItemsNoRange &) +{} +void +Dump::visit (TupleStructItemsRange &) +{} +void +Dump::visit (TupleStructPattern &) +{} + +void +Dump::visit (TuplePatternItemsMultiple &) +{} +void +Dump::visit (TuplePatternItemsRanged &) +{} +void +Dump::visit (TuplePattern &) +{} +void +Dump::visit (GroupedPattern &) +{} +void +Dump::visit (SlicePattern &) +{} + +void +Dump::visit (EmptyStmt &) +{} +void +Dump::visit (LetStmt &) +{} +void +Dump::visit (ExprStmtWithoutBlock &) +{} +void +Dump::visit (ExprStmtWithBlock &) +{} + +void +Dump::visit (TraitBound &) +{} +void +Dump::visit (ImplTraitType &) +{} +void +Dump::visit (TraitObjectType &) +{} +void +Dump::visit (ParenthesisedType &) +{} +void +Dump::visit (ImplTraitTypeOneBound &) +{} +void +Dump::visit (TupleType &) +{} +void +Dump::visit (NeverType &) +{} +void +Dump::visit (RawPointerType &) +{} +void +Dump::visit (ReferenceType &) +{} +void +Dump::visit (ArrayType &) +{} +void +Dump::visit (SliceType &) +{} +void +Dump::visit (InferredType &) +{} +void +Dump::visit (BareFunctionType &) +{} +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/hir/rust-hir-dump.h b/gcc/rust/hir/rust-hir-dump.h new file mode 100644 index 00000000000..8b9e8939a28 --- /dev/null +++ b/gcc/rust/hir/rust-hir-dump.h @@ -0,0 +1,193 @@ +// 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_HIR_DUMP_H +#define RUST_HIR_DUMP_H + +#include "rust-hir-visitor.h" +#include "rust-hir.h" +#include "rust-hir-full.h" + +namespace Rust { +namespace HIR { + +class Dump : public HIRFullVisitor +{ +public: + Dump (std::ostream &stream); + void go (HIR::Crate &crate); + +private: + std::ostream &stream; + std::size_t indent; // current indentation level + char indent_char = '\t'; + + virtual void visit (Lifetime &) override; + virtual void visit (LifetimeParam &) override; + virtual void visit (PathInExpression &) override; + virtual void visit (TypePathSegment &) override; + virtual void visit (TypePathSegmentGeneric &) override; + virtual void visit (TypePathSegmentFunction &) override; + virtual void visit (TypePath &) override; + virtual void visit (QualifiedPathInExpression &) override; + virtual void visit (QualifiedPathInType &) override; + + virtual void visit (LiteralExpr &) override; + virtual void visit (BorrowExpr &) override; + virtual void visit (DereferenceExpr &) override; + virtual void visit (ErrorPropagationExpr &) override; + virtual void visit (NegationExpr &) override; + virtual void visit (ArithmeticOrLogicalExpr &) override; + virtual void visit (ComparisonExpr &) override; + virtual void visit (LazyBooleanExpr &) override; + virtual void visit (TypeCastExpr &) override; + virtual void visit (AssignmentExpr &) override; + virtual void visit (CompoundAssignmentExpr &) override; + virtual void visit (GroupedExpr &) override; + + virtual void visit (ArrayElemsValues &) override; + virtual void visit (ArrayElemsCopied &) override; + virtual void visit (ArrayExpr &) override; + virtual void visit (ArrayIndexExpr &) override; + virtual void visit (TupleExpr &) override; + virtual void visit (TupleIndexExpr &) override; + virtual void visit (StructExprStruct &) override; + + virtual void visit (StructExprFieldIdentifier &) override; + virtual void visit (StructExprFieldIdentifierValue &) override; + + virtual void visit (StructExprFieldIndexValue &) override; + virtual void visit (StructExprStructFields &) override; + virtual void visit (StructExprStructBase &) override; + + virtual void visit (CallExpr &) override; + virtual void visit (MethodCallExpr &) override; + virtual void visit (FieldAccessExpr &) override; + virtual void visit (ClosureExprInner &) override; + virtual void visit (BlockExpr &) override; + virtual void visit (ClosureExprInnerTyped &) override; + virtual void visit (ContinueExpr &) override; + virtual void visit (BreakExpr &) override; + virtual void visit (RangeFromToExpr &) override; + virtual void visit (RangeFromExpr &) override; + virtual void visit (RangeToExpr &) override; + virtual void visit (RangeFullExpr &) override; + virtual void visit (RangeFromToInclExpr &) override; + virtual void visit (RangeToInclExpr &) override; + virtual void visit (ReturnExpr &) override; + virtual void visit (UnsafeBlockExpr &) override; + virtual void visit (LoopExpr &) override; + virtual void visit (WhileLoopExpr &) override; + virtual void visit (WhileLetLoopExpr &) override; + virtual void visit (ForLoopExpr &) override; + virtual void visit (IfExpr &) override; + virtual void visit (IfExprConseqElse &) override; + virtual void visit (IfExprConseqIf &) override; + virtual void visit (IfExprConseqIfLet &) override; + virtual void visit (IfLetExpr &) override; + virtual void visit (IfLetExprConseqElse &) override; + virtual void visit (IfLetExprConseqIf &) override; + virtual void visit (IfLetExprConseqIfLet &) override; + + virtual void visit (MatchExpr &) override; + virtual void visit (AwaitExpr &) override; + virtual void visit (AsyncBlockExpr &) override; + + virtual void visit (TypeParam &) override; + virtual void visit (ConstGenericParam &) override; + + virtual void visit (LifetimeWhereClauseItem &) override; + virtual void visit (TypeBoundWhereClauseItem &) override; + virtual void visit (Module &) override; + virtual void visit (ExternCrate &) override; + + virtual void visit (UseTreeGlob &) override; + virtual void visit (UseTreeList &) override; + virtual void visit (UseTreeRebind &) override; + virtual void visit (UseDeclaration &) override; + virtual void visit (Function &) override; + virtual void visit (TypeAlias &) override; + virtual void visit (StructStruct &) override; + virtual void visit (TupleStruct &) override; + virtual void visit (EnumItem &) override; + virtual void visit (EnumItemTuple &) override; + virtual void visit (EnumItemStruct &) override; + virtual void visit (EnumItemDiscriminant &) override; + virtual void visit (Enum &) override; + virtual void visit (Union &) override; + virtual void visit (ConstantItem &) override; + virtual void visit (StaticItem &) override; + virtual void visit (TraitItemFunc &) override; + virtual void visit (TraitItemConst &) override; + virtual void visit (TraitItemType &) override; + virtual void visit (Trait &) override; + virtual void visit (ImplBlock &) override; + + virtual void visit (ExternalStaticItem &) override; + virtual void visit (ExternalFunctionItem &) override; + virtual void visit (ExternBlock &) override; + + virtual void visit (LiteralPattern &) override; + virtual void visit (IdentifierPattern &) override; + virtual void visit (WildcardPattern &) override; + + virtual void visit (RangePatternBoundLiteral &) override; + virtual void visit (RangePatternBoundPath &) override; + virtual void visit (RangePatternBoundQualPath &) override; + virtual void visit (RangePattern &) override; + virtual void visit (ReferencePattern &) override; + + virtual void visit (StructPatternFieldTuplePat &) override; + virtual void visit (StructPatternFieldIdentPat &) override; + virtual void visit (StructPatternFieldIdent &) override; + virtual void visit (StructPattern &) override; + + virtual void visit (TupleStructItemsNoRange &) override; + virtual void visit (TupleStructItemsRange &) override; + virtual void visit (TupleStructPattern &) override; + + virtual void visit (TuplePatternItemsMultiple &) override; + virtual void visit (TuplePatternItemsRanged &) override; + virtual void visit (TuplePattern &) override; + virtual void visit (GroupedPattern &) override; + virtual void visit (SlicePattern &) override; + + virtual void visit (EmptyStmt &) override; + virtual void visit (LetStmt &) override; + virtual void visit (ExprStmtWithoutBlock &) override; + virtual void visit (ExprStmtWithBlock &) override; + + virtual void visit (TraitBound &) override; + virtual void visit (ImplTraitType &) override; + virtual void visit (TraitObjectType &) override; + virtual void visit (ParenthesisedType &) override; + virtual void visit (ImplTraitTypeOneBound &) override; + virtual void visit (TupleType &) override; + virtual void visit (NeverType &) override; + virtual void visit (RawPointerType &) override; + virtual void visit (ReferenceType &) override; + virtual void visit (ArrayType &) override; + virtual void visit (SliceType &) override; + virtual void visit (InferredType &) override; + virtual void visit (BareFunctionType &) override; +}; + +} // namespace HIR +} // namespace Rust + +#endif // !RUST_HIR_DUMP_H From patchwork Wed Aug 24 11:59:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56993 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 A66BF395C068 for ; Wed, 24 Aug 2022 12:05:09 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com [IPv6:2a00:1450:4864:20::42e]) by sourceware.org (Postfix) with ESMTPS id 7B524388550F; Wed, 24 Aug 2022 12:00:53 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 7B524388550F Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x42e.google.com with SMTP id a4so20519639wrq.1; Wed, 24 Aug 2022 05:00:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=DM/LY0TkNgOJ4YhoQ6i4iSo2wu9tJhSp7I5HRoVivf4=; b=pG+8NLpWT0waKyLwxCcyjwjjNHMjWAhX8h3bOS85rmHDW/Nio7QuoXcbkp9wRJ1Tj5 DKdmlfzEOgESiRbsILV7y/LNG0aXgAcw4GRUcgk0aMcV8V8INDARCtLmyqyDTzUi0Xz7 z3lKc8v/fwK90/K+2ObUYEVZj0kyh7KR4Rt7sEp6m7+3ZT2YXR0h0XXI+/7QJfywSlOL c6Rb9dhnQFXv+ZwPZqkuNulTRM8FciuRQllSC/bxEgqcXL4mS+4AU0NkPipan2hqb2ly Le1wqNZVYS3DKT/ctc01zXFhfUVp91uFQDETrW3cAO6GbvOlhsP4G9hVI2Vctoguj8Jc pvlw== 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; bh=DM/LY0TkNgOJ4YhoQ6i4iSo2wu9tJhSp7I5HRoVivf4=; b=vYFEaiNOvrgHW8hPj0GCynSeNDeKRQf/jD8zcfMgJGCmba+lbR8llKeYrlPQ4qUiwu EuZ1bB9uMGlVGz/cvEfWBhIXxzcF0zy+0OyvJdEuCKQ552Ovk8aICol73BNHuxaMV1SG uhs4ALbulD69SSBzeTwZC5CbtTjGRY91of7cFSeJD3mwSKD6cFYj/2eKWK0ubm0oAZUM N2Hmp7opHUQoOCb3EiuJ91CJe6+lcgOmCSYQudC/ObfIVmZMHba3zdNNRmc9drzNNSIo SoPEaSh0X0iEKiXAp3cjE/t1EI9QfM3/nCZ+mtkSM1sjGNVsECr/Cb8aUnKtwk8mndsx FjxA== X-Gm-Message-State: ACgBeo2arewPO3eKaoZ9psSzhIvqb5FeyqNGY6FFtP2vhwHhbW8tE65P oO2d3m87ao0MXb08n+VBBxkEqzh/JZA= X-Google-Smtp-Source: AA6agR4bfNeFA0kME98/9oqpGs/nTjmXOgD4x0I1D6413cSu39YV6EVV59Nr0JuamJtURq0kDg+yww== X-Received: by 2002:a5d:6a50:0:b0:225:5dd6:873f with SMTP id t16-20020a5d6a50000000b002255dd6873fmr6498136wrw.101.1661342451873; Wed, 24 Aug 2022 05:00:51 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:51 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 15/37] gccrs: Add wrapper for make_unique Date: Wed, 24 Aug 2022 12:59:34 +0100 Message-Id: <20220824115956.737931-16-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron This is a wrapper for make_unique we can likely get rid of this as there are other implementations available or simply keep using the unique_ptr constructor. --- gcc/rust/util/rust-make-unique.h | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 gcc/rust/util/rust-make-unique.h diff --git a/gcc/rust/util/rust-make-unique.h b/gcc/rust/util/rust-make-unique.h new file mode 100644 index 00000000000..f33f9125f89 --- /dev/null +++ b/gcc/rust/util/rust-make-unique.h @@ -0,0 +1,35 @@ +// 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_MAKE_UNIQUE_H +#define RUST_MAKE_UNIQUE_H + +#include + +namespace Rust { + +template +std::unique_ptr +make_unique (Ts &&... params) +{ + return std::unique_ptr (new T (std::forward (params)...)); +} + +} // namespace Rust + +#endif // RUST_MAKE_UNIQUE_H From patchwork Wed Aug 24 11:59:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56986 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 0F9763952498 for ; Wed, 24 Aug 2022 12:03:12 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com [IPv6:2a00:1450:4864:20::42a]) by sourceware.org (Postfix) with ESMTPS id 8DA083882159; Wed, 24 Aug 2022 12:00:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 8DA083882159 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x42a.google.com with SMTP id az27so465272wrb.6; Wed, 24 Aug 2022 05:00:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=t6aFODSRTT8upYExcW7j4bXWFKP99Dlm2IDdQsvVzPM=; b=KMlYxvTjMELGSE5BnzWfI3EhzvTk8vTrEjkbPAuCvpAFMV4Pe540bTzAmMLEwmHoI6 BEe8syYJqCMTPIhVHltBk6dcKXMRv2s7z7E8tVYZkRTKNaTXv0FIsg9EEqegtdr+vNvi HNyjioLrAHx8ZzSzBsDszZax13BdHhjZy0lx/A44yoXP0i3YS+YDPqCyv/q9QBIFocfq VF3vIlBeBLqkKJe9tzEYaBvEmOlWjyvRIWcl0N6xNUZ78qKeJS4XJkZe2DmsNsCgN5Ww RF6LX6Ar6XI0h9xom+GG6YpywLAEQXryCNmn2+vP7ACsdL8KABFFCmaV5LILcwuCG4P0 aPew== 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; bh=t6aFODSRTT8upYExcW7j4bXWFKP99Dlm2IDdQsvVzPM=; b=GpxeRRt8D0PFhmya0hvOjnGO4ppDsKPWEv88zjYP80L6yECVsvXRTovvnOO8nglo5J 0pV+PeyNx+iS7ysTkfuy5S3/sZgtKYwOruWusSnr1zVrYG5glQRtw1ioHT59kvsRsfMi 7v5n+5YVVHTpc+Q50cgQXqbzv1ZFuuq8wXAWaFhtpNr7jpCULxLXa75xblDaLPCa1czu 01jXBVe2JkD8n/+vNGIPxuff9FzeGKxj2VeX/6Zt2M+BGa3aNIxWfHSQIb+114hTApL2 2wwqZ+vrGXXi6WAutROUs/+RZBJM8jvNkbCVAsNGgvTP+IddZ75VS3Y8DX5h1mxOBL+l 9ifw== X-Gm-Message-State: ACgBeo3ef6/UecU/78C3I8ZDmdXlmSBu+VJLClOTlfer4rvc1+T5nQtj w2m2OPHZwpIIDI7r4bto5CCa5RExcE8= X-Google-Smtp-Source: AA6agR5ZcUoPENdL4We5qL7HiySQvUz265NZCBSi7MnhhCSdORVsv2J8essCBUlxxMAFxFMq2EISNQ== X-Received: by 2002:adf:eb10:0:b0:225:70d5:e994 with SMTP id s16-20020adfeb10000000b0022570d5e994mr1640735wrn.425.1661342453092; Wed, 24 Aug 2022 05:00:53 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:52 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 16/37] gccrs: Add port of FNV hash used during legacy symbol mangling Date: Wed, 24 Aug 2022 12:59:35 +0100 Message-Id: <20220824115956.737931-17-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron This hash was ported from the go runime as we needed a hash for the legacy symbol mangling system. Which means all symbols in Rust contain a hash of some metadata for uniqueness on generic functions. --- gcc/rust/util/fnv-hash.h | 95 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 gcc/rust/util/fnv-hash.h diff --git a/gcc/rust/util/fnv-hash.h b/gcc/rust/util/fnv-hash.h new file mode 100644 index 00000000000..78e54c99411 --- /dev/null +++ b/gcc/rust/util/fnv-hash.h @@ -0,0 +1,95 @@ +// 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_FNV_HASH_H +#define RUST_FNV_HASH_H + +namespace Rust { +namespace Hash { + +const uint64_t offset128Lower = 0x62b821756295c58d; +const uint64_t offset128Higher = 0x6c62272e07bb0142; +const uint64_t prime128Lower = 0x13b; +const uint64_t prime128Shift = 24; + +// ported from https://github.com/golang/go/blob/master/src/hash/fnv/fnv.go +class FNV128 +{ +public: + FNV128 () { reset (); } + + void reset () + { + buf[0] = offset128Higher; + buf[1] = offset128Lower; + } + + void write (const unsigned char *in, size_t len) + { + for (size_t i = 0; i < len; i++) + { + unsigned char c = in[i]; + + // https://stackoverflow.com/questions/28868367/getting-the-high-part-of-64-bit-integer-multiplication + uint64_t a = prime128Lower; + uint64_t b = buf[1]; + + uint64_t a_lo = (uint32_t) a; + uint64_t a_hi = a >> 32; + uint64_t b_lo = (uint32_t) b; + uint64_t b_hi = b >> 32; + + uint64_t a_x_b_hi = a_hi * b_hi; + uint64_t a_x_b_mid = a_hi * b_lo; + uint64_t b_x_a_mid = b_hi * a_lo; + uint64_t a_x_b_lo = a_lo * b_lo; + + uint64_t carry_bit + = ((uint64_t) (uint32_t) a_x_b_mid + (uint64_t) (uint32_t) b_x_a_mid + + (a_x_b_lo >> 32)) + >> 32; + + uint64_t multhi + = a_x_b_hi + (a_x_b_mid >> 32) + (b_x_a_mid >> 32) + carry_bit; + + uint64_t s0 = multhi; // high + uint64_t s1 = prime128Lower * buf[1]; // low + + s0 += buf[1] << (prime128Shift + prime128Lower * buf[0]); + + // Update the values + buf[1] = s1; + buf[0] = s0; + buf[1] ^= (uint64_t) c; + } + } + + void sum (uint64_t *hi, uint64_t *lo) const + { + *hi = buf[0]; + *lo = buf[1]; + } + +private: + uint64_t buf[2]; +}; + +} // namespace Hash +} // namespace Rust + +#endif // RUST_FNV_HASH_H From patchwork Wed Aug 24 11:59:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56995 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 A6D1B38207AB for ; Wed, 24 Aug 2022 12:05:44 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x42f.google.com (mail-wr1-x42f.google.com [IPv6:2a00:1450:4864:20::42f]) by sourceware.org (Postfix) with ESMTPS id 121D23885C22; Wed, 24 Aug 2022 12:00:56 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 121D23885C22 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x42f.google.com with SMTP id b5so16204089wrr.5; Wed, 24 Aug 2022 05:00:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=faMW4xAPda93TRGR2QHBH3TEDPQ193jx4GkOCpJopPc=; b=UD/DSZ7aUXB51nEDg1Z0qQUK8duxWuWdbn/dJToc3vPQFjoPMSWOVuAVqIZ7uKTZ2z vPcZYcE8MrpF3PXZqj7ztpf9dM0sHO8BRjgiIWRUD0JHcffPRUFg1SsqMusu9Q0FLz+T X2e7PsHyRIo+iGUxFzIYa5iG8d3jAfpXuvXY4jGx4NNtQ/3FnbDDlOmQm9i7/VCol7Sl sKfLH7qkr+IKX3Li+qGD9jARl3kPsoa3lCckxpqxmSfLSlE9HLihSQ2XNoiTNV1OSn3I 4bQe/2iasEY9j7R/N8NNAVB73nsb9UiuvAXcVTTKDrwxMK8039ATtT0LpBeyIR8mJWG+ WiLQ== 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; bh=faMW4xAPda93TRGR2QHBH3TEDPQ193jx4GkOCpJopPc=; b=gx+/X68j7+jhEAsteZ6yMNHA5jyPQOQATYxaqUHQguu8/B23fgWCxtQSeSRkcxjlMl LPzIDLMlvi5NKYSCdPWtI3BZW0xqo4HA0GMOU4hnUEA7M6DTC8HTXXoxJNoOaYtOE7Z/ p5wj+EwpSyVs+TZa8enNusZgO5D3qDb3DMNU9r8Y37NG6YuIdQOOZuftycZYqxj8mHIz MSXvBp0qGLcm93oEr95Un8iHaGAY8ZLlYJL9vddv1LFpvsy+gj1GDBl7y4BzHWx01xkd NKgNqttyhyljGOTwGaQZJTVXWQnQa0ULLVV9ts9My9H8d+9fqj98gbgtjxtae2Y1qVCj AKBA== X-Gm-Message-State: ACgBeo2ZhVEuq0JZHnTemSouc/kmVCYXlfoJsK7x9Ois4xSyEPePbCpK wjb0y5QEWKdXwlxwREr0+6BfbZvgwSc= X-Google-Smtp-Source: AA6agR4lsi4P3oSMUgzFZ0d6t57oGbwsQJuhJtXFC/7Phw+8EcjmiEC2rZPu+Z8/JWgG+lRGLu6fwA== X-Received: by 2002:a5d:648c:0:b0:220:7aa9:a13c with SMTP id o12-20020a5d648c000000b002207aa9a13cmr15504684wri.269.1661342454180; Wed, 24 Aug 2022 05:00:54 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:53 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 17/37] gccrs: Add Rust ABI enum helpers Date: Wed, 24 Aug 2022 12:59:36 +0100 Message-Id: <20220824115956.737931-18-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron This is a simple helper over an enum of possible ABI options in Rust. --- gcc/rust/util/rust-abi.cc | 72 +++++++++++++++++++++++++++++++++++++++ gcc/rust/util/rust-abi.h | 45 ++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 gcc/rust/util/rust-abi.cc create mode 100644 gcc/rust/util/rust-abi.h diff --git a/gcc/rust/util/rust-abi.cc b/gcc/rust/util/rust-abi.cc new file mode 100644 index 00000000000..6477c3790af --- /dev/null +++ b/gcc/rust/util/rust-abi.cc @@ -0,0 +1,72 @@ +// 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-abi.h" + +namespace Rust { + +Rust::ABI +get_abi_from_string (const std::string &abi) +{ + if (abi.compare ("rust") == 0) + return Rust::ABI::RUST; + else if (abi.compare ("rust-intrinsic") == 0) + return Rust::ABI::INTRINSIC; + else if (abi.compare ("C") == 0) + return Rust::ABI::C; + else if (abi.compare ("cdecl") == 0) + return Rust::ABI::CDECL; + else if (abi.compare ("stdcall") == 0) + return Rust::ABI::STDCALL; + else if (abi.compare ("fastcall") == 0) + return Rust::ABI::FASTCALL; + else if (abi.compare ("sysv64") == 0) + return Rust::ABI::SYSV64; + else if (abi.compare ("win64") == 0) + return Rust::ABI::WIN64; + + return Rust::ABI::UNKNOWN; +} + +std::string +get_string_from_abi (Rust::ABI abi) +{ + switch (abi) + { + case Rust::ABI::RUST: + return "rust"; + case Rust::ABI::INTRINSIC: + return "rust-intrinsic"; + case Rust::ABI::C: + return "C"; + case Rust::ABI::CDECL: + return "cdecl"; + case Rust::ABI::STDCALL: + return "stdcall"; + case Rust::ABI::FASTCALL: + return "fastcall"; + case Rust::ABI::SYSV64: + return "sysv64"; + case Rust::ABI::WIN64: + return "win64"; + + case Rust::ABI::UNKNOWN: + return "unknown"; + } + return "unknown"; +} + +} // namespace Rust diff --git a/gcc/rust/util/rust-abi.h b/gcc/rust/util/rust-abi.h new file mode 100644 index 00000000000..d794cc35fb3 --- /dev/null +++ b/gcc/rust/util/rust-abi.h @@ -0,0 +1,45 @@ +// 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_ABI_OPTIONS_H +#define RUST_ABI_OPTIONS_H + +#include "rust-system.h" + +namespace Rust { + +enum ABI +{ + UNKNOWN, + RUST, + INTRINSIC, + C, + CDECL, + STDCALL, + FASTCALL, + WIN64, + SYSV64 +}; + +extern Rust::ABI +get_abi_from_string (const std::string &abi); + +extern std::string +get_string_from_abi (Rust::ABI abi); + +} // namespace Rust + +#endif // RUST_ABI_OPTIONS_H From patchwork Wed Aug 24 11:59:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56988 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 BEA6A395C06C for ; Wed, 24 Aug 2022 12:04:08 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com [IPv6:2a00:1450:4864:20::329]) by sourceware.org (Postfix) with ESMTPS id A7CC53836026; Wed, 24 Aug 2022 12:00:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org A7CC53836026 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wm1-x329.google.com with SMTP id ay12so8657004wmb.1; Wed, 24 Aug 2022 05:00:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=puZaanwb1A2g3ZEuqMIUgjURr1+LwMNAm7ixujYPsUs=; b=F4yY0RFHYIEKMLZrM6E6k0pf60eg5lCOv6DBk12m/opUUgl/BSO5oLas2NWkBJgPub FxJGJ+YO5zXXf6NtUBlJ3YUiVQ+zHF2DnQuLFrqUQbjm1/dnK2TnVLdp+Sh/+NJgAIwp Y3jvK1byPLdb3R0kOcGg4Gcv5cuyZK/q7dwUC6/n+9UD6CR0FxEt0/5Z4ULYRfqtBbAO G9efrCX88lksQlAXYH+p87Rk3yjfaqqNQzcuBXiSj2ADEoADTlBzPxHcgszQOSBh6xTI +2xYrZ06x4JwnGP0xcubzgHH0/eTRl0SP3yh9xnswjh9t5hlDjBK7j5LvJ+02CuJ1/BA Sh8g== 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; bh=puZaanwb1A2g3ZEuqMIUgjURr1+LwMNAm7ixujYPsUs=; b=DnYByl2NYtI0RM47hFFs7gyvX3mSdRKjcvboxNJbhSJv987oU++XFLNiNCaD8+9L3r palkOgMNfO6DH1N+bEsbq0PlQtJ4labtlkCYTBR9rWflAPCpP8A2TPfX1ynTDlq3H1Sy IVRdA/rDtvl+yQPZVLdF0MBCffKXfMTnyGLngooXiUknc4KLpnBFHl5YVbNRjJo/tCU0 jMwM4Ai4sFkSXTF3LKBSmCH7yLYMl4uQHIymx1twt1KNpUNnXueFOa3PSd7Q6Kx0Hdsh 9CXdY44ImU0pd8D7GMQz8Ydt7LvY0j0PfxuwkiPph9aS5QiIILy3/b4qmJDBLmb6ei3c vRuA== X-Gm-Message-State: ACgBeo1XhWMk8PQEfstqUOB61K8ELP9yLHN6ZJvXggMzac77LR+AgVgJ lxzXOyEl8UXpLZY/bWgfaUkvt3HUhHQ= X-Google-Smtp-Source: AA6agR7JElFGSj8IYGXMKOPhurfbsT1LI80KkxdIn+tJqNDibJb2NWXjFuFdIXP3+L6br/fsEfCSnw== X-Received: by 2002:a05:600c:4fc2:b0:3a5:c491:5ee1 with SMTP id o2-20020a05600c4fc200b003a5c4915ee1mr4902135wmq.62.1661342454932; Wed, 24 Aug 2022 05:00:54 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:54 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 18/37] gccrs: Add Base62 implementation Date: Wed, 24 Aug 2022 12:59:37 +0100 Message-Id: <20220824115956.737931-19-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: Arthur Cohen , gcc-rust@gcc.gnu.org Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Arthur Cohen Used for V0 symbol mangling scheme which. --- gcc/rust/util/rust-base62.cc | 46 ++++++++++++++++++++++++++++++++++++ gcc/rust/util/rust-base62.h | 34 ++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 gcc/rust/util/rust-base62.cc create mode 100644 gcc/rust/util/rust-base62.h diff --git a/gcc/rust/util/rust-base62.cc b/gcc/rust/util/rust-base62.cc new file mode 100644 index 00000000000..bdab23338c3 --- /dev/null +++ b/gcc/rust/util/rust-base62.cc @@ -0,0 +1,46 @@ +// 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 +// . + +#include "rust-base62.h" + +namespace Rust { + +std::string +base62_integer (uint64_t value) +{ + const static std::string base_64 + = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@$"; + std::string buffer (128, '\0'); + size_t idx = 0; + size_t base = 62; + + do + { + buffer[idx] = base_64[(value % base)]; + idx++; + value = value / base; + } + while (value != 0); + + std::reverse (buffer.begin (), buffer.begin () + idx); + return buffer.substr (0, idx); +} + +} // namespace Rust + +// FIXME: Add unit testing using the selftest framework diff --git a/gcc/rust/util/rust-base62.h b/gcc/rust/util/rust-base62.h new file mode 100644 index 00000000000..fa610d3e5a4 --- /dev/null +++ b/gcc/rust/util/rust-base62.h @@ -0,0 +1,34 @@ +// 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_BASE62_H +#define RUST_BASE62_H + +#include "rust-system.h" + +namespace Rust { + +/** + * Get the Base62 representation of an integer + */ +std::string +base62_integer (uint64_t value); + +} // namespace Rust + +#endif /* !RUST_BASE62_H */ From patchwork Wed Aug 24 11:59:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56990 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 0277539960C0 for ; Wed, 24 Aug 2022 12:04:30 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x333.google.com (mail-wm1-x333.google.com [IPv6:2a00:1450:4864:20::333]) by sourceware.org (Postfix) with ESMTPS id 974003895FF4; Wed, 24 Aug 2022 12:00:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 974003895FF4 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wm1-x333.google.com with SMTP id r83-20020a1c4456000000b003a5cb389944so781065wma.4; Wed, 24 Aug 2022 05:00:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=KwRHVm4crOE15Z+PSJan3BiHSbt+LVB39MQHRTyUAB4=; b=V26VJnH/GXTw/YSP1h9f/4u4ehZREEVRjzUbU9ruN6U2MuEDSsjoNU/xMZLjHDJh/J i3i4VFv/lDkczAgzbx/6y+p0hcovqSBMi78/xA4LAJjJSezr3oKTCY9LBeH5OggoxpWO lmIhpM9LhSWJWCl9zPmAjhOSB9LtjcUX3hfC9Xb/Rt2bxBvt4D0W92puZP8UI6jIOp26 xyiP/UCX9VKgFvzjIwzJyoLdBD23HA7t6ty6kWov/Nk54ltuxLUWG4utxLcjbTEr2ZCc BPvOkbUQa/n1NHeJggbeXLN5Vi6y69qsq1tn/QQJfU/7VUtIcKrloYEb6rLM0Q62DpsU vTWA== 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; bh=KwRHVm4crOE15Z+PSJan3BiHSbt+LVB39MQHRTyUAB4=; b=gDS2DzYcRPXxnlxoUZl5A6ttM1i7nmXscjPCp+QSr0vJuSF9vPSpU9q3ZtyBG8muxS 6ajjYb6wdNtFvnXMtYLx1ybUjkW73CRo6vbTeH1oGCoygPQDuC1ct5aYkecbL3xSA/bX 7p9S3QYQmnmznAlAxYjoUzxejXJlMbVtxgCq+4Hh6jFWrKE5jedDXze2DJOw7w3VCOL/ DwKCM3DVpFsD0jvPDcz60xPr2tavreU+bqP4ouO+f+jtX4+0Si5qKKp67ZORiV0rX/Qc PON7a2A0gRcx69rdz8HrUxXi9BZHM1z4owqulg8ZVI0ob8DlV7JVJJgYs0fw/8DqTZ19 7F/w== X-Gm-Message-State: ACgBeo3TCKegvwlQpNwGGGlnLbZ9PMKc8S9jOxbCm8TuOG4FjiWpm+H5 N0jBVBaJ6HkbcuhR1p+p3foaie7ytO4= X-Google-Smtp-Source: AA6agR7L8FnM8dySzuBAw02gEDARfcI1toiadiZjTO9p4d35dqlJWX7ZIYS6tABa1DwB87LR5rojFQ== X-Received: by 2002:a1c:7916:0:b0:3a6:3540:5b3c with SMTP id l22-20020a1c7916000000b003a635405b3cmr4924653wme.178.1661342456003; Wed, 24 Aug 2022 05:00:56 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:55 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 19/37] gccrs: Add implementation of Optional Date: Wed, 24 Aug 2022 12:59:38 +0100 Message-Id: <20220824115956.737931-20-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: Arthur Cohen , gcc-rust@gcc.gnu.org Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Arthur Cohen Add an Optional class to improve error handling --- gcc/rust/util/rust-optional-test.cc | 111 +++++++++++ gcc/rust/util/rust-optional.h | 278 ++++++++++++++++++++++++++++ 2 files changed, 389 insertions(+) create mode 100644 gcc/rust/util/rust-optional-test.cc create mode 100644 gcc/rust/util/rust-optional.h diff --git a/gcc/rust/util/rust-optional-test.cc b/gcc/rust/util/rust-optional-test.cc new file mode 100644 index 00000000000..9d5b4ba5735 --- /dev/null +++ b/gcc/rust/util/rust-optional-test.cc @@ -0,0 +1,111 @@ +// 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 +// . + +#include "rust-optional.h" + +#include "config.h" +#include "selftest.h" + +#if CHECKING_P + +static void +rust_optional_create () +{ + auto opt = Rust::Optional::some (15); + + ASSERT_TRUE (opt.is_some ()); + ASSERT_EQ (opt.get (), 15); + + Rust::Optional const_opt = Rust::Optional::some (15); + const int &value = const_opt.get (); + + ASSERT_EQ (value, 15); +} + +static void +rust_optional_operators () +{ + auto opt = Rust::Optional::some (15); + + // as bool + ASSERT_TRUE (opt); + + // deref + ASSERT_EQ (*opt, 15); + + class Methodable + { + public: + int method () { return 15; } + }; + + auto m_opt = Rust::Optional::some (Methodable ()); + ASSERT_EQ (m_opt->method (), 15); +} + +static void +rust_optional_take () +{ + auto opt = Rust::Optional::some (15); + auto value = opt.take (); + + ASSERT_EQ (value, 15); + ASSERT_TRUE (opt.is_none ()); +} + +static void +rust_optional_map () +{ + auto opt = Rust::Optional::some (15); + auto twice = opt.map ([] (int value) { return value * 2; }); + + ASSERT_FALSE (opt); + ASSERT_TRUE (twice); + ASSERT_EQ (*twice, 30); +} + +static void +rust_optional_reference () +{ + auto value = std::vector (); + value.emplace_back ("rust"); + value.emplace_back ("+"); + value.emplace_back ("gcc"); + value.emplace_back ("="); + value.emplace_back ("<3"); + + auto opt = Rust::Optional &>::some (value); + + ASSERT_EQ (opt->at (0), "rust"); + ASSERT_EQ (opt->at (2), "gcc"); +} + +#endif /* #if CHECKING_P */ + +void +rust_optional_test () +{ +#if CHECKING_P + rust_optional_create (); + rust_optional_operators (); + rust_optional_take (); + rust_optional_map (); + rust_optional_reference (); + +#endif /* #if CHECKING_P */ +} diff --git a/gcc/rust/util/rust-optional.h b/gcc/rust/util/rust-optional.h new file mode 100644 index 00000000000..56465400250 --- /dev/null +++ b/gcc/rust/util/rust-optional.h @@ -0,0 +1,278 @@ +// 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_OPTIONAL_H +#define RUST_OPTIONAL_H + +#include "config.h" +#include "rust-system.h" + +#include "selftest.h" + +namespace Rust { + +/** + * Tagged union to try and simulate a sum type. This is safer and more ergonomic + * than one of the two alternatives we're currently using in the compiler: + * + * 1. Storing a raw pointer, which can be `nullptr` or valid + * + * This is wildly unsafe, and usable in conjunction with local references, stack + * variables, or pointers managed elsewhere, which can cause crashes, hard to + * debug issues or undefined behavior. Likewise, if you do not check for the + * pointer's validity, this will cause a crash. + * + * 2. Storing an extra boolean alongside the object + * + * This causes implementors to use a "dummy object": Either an empty version or + * an error version. But what happens if what you really wanted to store was + * the empty or error version? You can also easily incorporate logic bugs if you + * forget to check for the associated boolean. + * + * The `Optional` type has the same "ergonomic" cost: You need to check + * whether your option is valid or not. However, the main advantage is that it + * is more restrictive: You can only acess the member it contains "safely". + * It is similar to storing a value + an associated boolean, but has the + * advantage of making up only one member in your class. + * You also benefit from some helper methods such as `map()`. + * + * You also get helper functions and operator overloading to "seamlessly" + * replace raw pointer alternatives. + * + * ```c++ + * MyType *raw_pointer = something_that_can_fail(); + * if (raw_pointer) + * raw_pointer->method(); + * + * // or + * + * Optional opt = something_that_can_fail2(); + * if (opt) + * opt->method(); + * + * // equivalent to + * + * if (opt.is_some()) + * opt.get().method(); + * ``` + */ +template class Optional +{ +private: + struct Empty + { + }; + + enum Kind + { + Some, + None + } kind; + + union Content + { + Empty empty; + T value; + + Content () = default; + } content; + + Optional (Kind kind, Content content) : kind (kind), content (content) {} + +public: + Optional (const Optional &other) = default; + Optional &operator= (const Optional &other) = default; + Optional (Optional &&other) = default; + + static Optional some (T value) + { + Content content; + content.value = value; + + return Optional (Kind::Some, content); + } + + static Optional none () + { + Content content; + content.empty = Empty (); + + return Optional (Kind::None, content); + } + + bool is_some () const { return kind == Kind::Some; } + bool is_none () const { return !is_some (); } + + /** + * Enable boolean-like comparisons. + */ + operator bool () { return is_some (); } + + /** + * Enables dereferencing to access the contained value + */ + T &operator* () { return get (); } + const T &operator* () const { return get (); } + T *operator-> () { return &get (); } + const T *operator-> () const { return &get (); } + + const T &get () const + { + rust_assert (is_some ()); + + return content.value; + } + + T &get () + { + rust_assert (is_some ()); + + return content.value; + } + + T take () + { + rust_assert (is_some ()); + + auto to_return = std::move (content.value); + + content.empty = Empty (); + kind = Kind::None; + + return to_return; + } + + template Optional map (std::function functor) + { + if (is_none ()) + return Optional::none (); + + auto value = functor (take ()); + + return Optional::some (value); + } +}; + +template class Optional +{ +private: + struct Empty + { + }; + + enum Kind + { + Some, + None + } kind; + + union Content + { + Empty empty; + T *value; + + Content () = default; + } content; + + Optional (Kind kind, Content content) : kind (kind), content (content) {} + +public: + Optional (const Optional &other) = default; + Optional (Optional &&other) = default; + + static Optional some (T &value) + { + Content content; + content.value = &value; + + return Optional (Kind::Some, content); + } + + static Optional none () + { + Content content; + content.empty = Empty (); + + return Optional (Kind::None, content); + } + + bool is_some () const { return kind == Kind::Some; } + bool is_none () const { return !is_some (); } + + // FIXME: Can we factor this in a single class? + + /** + * Enable boolean-like comparisons. + */ + operator bool () { return is_some (); } + + /** + * Enables dereferencing to access the contained value + */ + T &operator* () { return get (); } + const T &operator* () const { return get (); } + T *operator-> () { return &get (); } + const T *operator-> () const { return &get (); } + + const T &get () const + { + rust_assert (is_some ()); + + return *content.value; + } + + T &get () + { + rust_assert (is_some ()); + + return *content.value; + } + + T &take () + { + rust_assert (is_some ()); + + auto to_return = std::move (content.value); + + content.empty = Empty (); + kind = Kind::None; + + return *to_return; + } + + template Optional map (std::function functor) + { + if (is_none ()) + return Optional::none (); + + auto value = functor (take ()); + + return Optional::some (value); + } +}; + +} // namespace Rust + +#ifdef CHECKING_P + +void +rust_optional_test (); + +#endif // !CHECKING_P + +#endif // !RUST_OPTIONAL_H From patchwork Wed Aug 24 11:59:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56991 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 3982D382E4D8 for ; Wed, 24 Aug 2022 12:05:07 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x436.google.com (mail-wr1-x436.google.com [IPv6:2a00:1450:4864:20::436]) by sourceware.org (Postfix) with ESMTPS id 266D0389838A; Wed, 24 Aug 2022 12:00:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 266D0389838A Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x436.google.com with SMTP id z16so1690488wrh.10; Wed, 24 Aug 2022 05:00:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=RY3YJhHtip1i04D2u2k509zizlQDFqVGq52kkN/iIUk=; b=UMyvYoNA+SQh5wwmUJJb1ej5aHK9XEYAkY/gJgzDM15S1AkeOjnf9nNQoW9abtEpTo xiUyU2ww/TuvEbOnSgbVhSre8DzeqOm6hgVyZFPWsbSh8l/EYI8slSTXvYeB6v6b9q/Y N1+RQ2bbmfkELb7jXkDGmay6789yuKVcrwrzp++cnmYayKzb1demRC8Tqpc/r00Dv/Uw 6woVKdRLooBS0K27On6IVV9Ov0ixC3fDzE4P+Yt3E2WwiRFV75ejBM9BjL8SOYryyYxU Yq0ZFQ/IigvGJzAITyBnEJcaQFNafakGT5tDuz0GUdDGV/aIFDnxwEaAJW/UG6eusvmX QQgA== 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; bh=RY3YJhHtip1i04D2u2k509zizlQDFqVGq52kkN/iIUk=; b=C33UYW9rNTK5zxIvaE5MAz3WzaCKsaEZNx69c6x7OP/ZAfwEAoNB0tq7zcZVt5C/Nj lAhHK3KSjcnZiwXeCw+SLTRolqlGK2Gat+spFetU3erc56DzYehWwTruZj0Kgt9fVOpG 9suKzREbBf8FubGhJP9ssSoInTgEs/ivO/akmfXfBrMuWmTDLPsfjGswquplgZWavRal p3RppEzcN3WyP1NeZdkM33ZquiqfpOfBiiWAeRVckGNp/dnluM07oPISB0ECDpe71YzD p3QA6ce1lJW0WKixZ+Lne0BHs1wJZp8OnhzEwR5iDiIhStCLa0+B/0SdWa3AdnSJ2umP wIlw== X-Gm-Message-State: ACgBeo39wEy4JRMAYCzwCM8pshuDtCN61k64dMNE2f/12ZGWzOhXJPY4 UbyQoe2ZoMzyJxE4JQtL8M5jMsEt3NI= X-Google-Smtp-Source: AA6agR6Vb3gBfKTUv/e0XuiKKH0i1Zz5U1UKyFxKU4GLm2ElOHGk5bru4BcC4XFqj2iCqav/MxbIaw== X-Received: by 2002:a05:6000:1e0f:b0:225:4052:3a68 with SMTP id bj15-20020a0560001e0f00b0022540523a68mr12091477wrb.707.1661342457125; Wed, 24 Aug 2022 05:00:57 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:56 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 20/37] gccrs: Add attributes checker Date: Wed, 24 Aug 2022 12:59:39 +0100 Message-Id: <20220824115956.737931-21-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: Arthur Cohen , gcc-rust@gcc.gnu.org Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Arthur Cohen The attribute checker is responsible for checking the validity of various attributes including built-in ones. It is currently unfinished and will receive some modifications, as well as become the host of some existing code in the compiler which needs to be refactored. One of its responsibilities is to make sure that arguments given to built-in attributes are correct, or contain the correct type of information. This visitor also checks that an attribute is allowed to be used in the current particular context. --- gcc/rust/util/rust-attributes.cc | 839 +++++++++++++++++++++++++++++++ gcc/rust/util/rust-attributes.h | 270 ++++++++++ 2 files changed, 1109 insertions(+) create mode 100644 gcc/rust/util/rust-attributes.cc create mode 100644 gcc/rust/util/rust-attributes.h diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc new file mode 100644 index 00000000000..bf4bb2fbfe9 --- /dev/null +++ b/gcc/rust/util/rust-attributes.cc @@ -0,0 +1,839 @@ +// 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 +// . + +#include "rust-attributes.h" +#include "rust-ast.h" +#include "rust-ast-full.h" +#include "rust-diagnostics.h" +#include "safe-ctype.h" + +namespace Rust { +namespace Analysis { + +// https://doc.rust-lang.org/stable/nightly-rustc/src/rustc_feature/builtin_attrs.rs.html#248 +static const BuiltinAttrDefinition __definitions[] = { + {"inline", CODE_GENERATION}, + {"cold", CODE_GENERATION}, + {"cfg", EXPANSION}, + {"cfg_attr", EXPANSION}, + {"deprecated", STATIC_ANALYSIS}, + {"allow", STATIC_ANALYSIS}, + {"doc", HIR_LOWERING}, + {"must_use", STATIC_ANALYSIS}, + {"lang", HIR_LOWERING}, + {"link_section", CODE_GENERATION}, + {"no_mangle", CODE_GENERATION}, + {"repr", CODE_GENERATION}, + {"path", EXPANSION}, +}; + +BuiltinAttributeMappings * +BuiltinAttributeMappings::get () +{ + static BuiltinAttributeMappings *instance = nullptr; + if (instance == nullptr) + instance = new BuiltinAttributeMappings (); + + return instance; +} + +const BuiltinAttrDefinition & +BuiltinAttributeMappings::lookup_builtin (const std::string &attr_name) const +{ + auto it = mappings.find (attr_name); + if (it == mappings.end ()) + return BuiltinAttrDefinition::error_node (); + + return it->second; +} + +BuiltinAttributeMappings::BuiltinAttributeMappings () +{ + size_t ndefinitions = sizeof (__definitions) / sizeof (BuiltinAttrDefinition); + for (size_t i = 0; i < ndefinitions; i++) + { + const BuiltinAttrDefinition &def = __definitions[i]; + mappings.insert ({def.name, def}); + } +} + +AttributeChecker::AttributeChecker () {} + +void +AttributeChecker::go (AST::Crate &crate) +{ + check_attributes (crate.get_inner_attrs ()); + + for (auto &item : crate.items) + item->accept_vis (*this); +} + +static bool +is_builtin (const AST::Attribute &attribute, BuiltinAttrDefinition &builtin) +{ + auto &segments = attribute.get_path ().get_segments (); + + // Builtin attributes always have a single segment. This avoids us creating + // strings all over the place and performing a linear search in the builtins + // map + if (segments.size () != 1) + return false; + + builtin = BuiltinAttributeMappings::get ()->lookup_builtin ( + segments.at (0).get_segment_name ()); + + return !builtin.is_error (); +} + +/** + * Check that the string given to #[doc(alias = ...)] or #[doc(alias(...))] is + * valid. + * + * This means no whitespace characters other than spaces and no quoting + * characters. + */ +static void +check_doc_alias (const std::string &alias_input, const Location &locus) +{ + // FIXME: The locus here is for the whole attribute. Can we get the locus + // of the alias input instead? + for (auto c : alias_input) + if ((ISSPACE (c) && c != ' ') || c == '\'' || c == '\"') + { + auto to_print = std::string (1, c); + switch (c) + { + case '\n': + to_print = "\\n"; + break; + case '\t': + to_print = "\\t"; + break; + default: + break; + } + rust_error_at (locus, + "invalid character used in %<#[doc(alias)]%> input: %qs", + to_print.c_str ()); + } + + if (alias_input.empty ()) + return; + + if (alias_input.front () == ' ' || alias_input.back () == ' ') + rust_error_at (locus, + "%<#[doc(alias)]%> input cannot start or end with a space"); +} + +static void +check_doc_attribute (const AST::Attribute &attribute) +{ + if (!attribute.has_attr_input ()) + { + rust_error_at ( + attribute.get_locus (), + // FIXME: Improve error message here. Rustc has a very good one + "%<#[doc]%> cannot be an empty attribute"); + return; + } + + switch (attribute.get_attr_input ().get_attr_input_type ()) + { + case AST::AttrInput::LITERAL: + case AST::AttrInput::META_ITEM: + break; + // FIXME: Handle them as well + + case AST::AttrInput::TOKEN_TREE: { + // FIXME: This doesn't check for #[doc(alias(...))] + const auto &option = static_cast ( + attribute.get_attr_input ()); + auto *meta_item = option.parse_to_meta_item (); + + for (auto &item : meta_item->get_items ()) + { + if (item->is_key_value_pair ()) + { + auto name_value + = static_cast (item.get ()) + ->get_name_value_pair (); + + // FIXME: Check for other stuff than #[doc(alias = ...)] + if (name_value.first == "alias") + check_doc_alias (name_value.second, attribute.get_locus ()); + } + } + break; + } + } +} + +void +AttributeChecker::check_attribute (const AST::Attribute &attribute) +{ + BuiltinAttrDefinition result; + + // This checker does not check non-builtin attributes + if (!is_builtin (attribute, result)) + return; + + // TODO: Add checks here for each builtin attribute + // TODO: Have an enum of builtins as well, switching on strings is annoying + // and costly + if (result.name == "doc") + check_doc_attribute (attribute); +} + +void +AttributeChecker::check_attributes (const AST::AttrVec &attributes) +{ + for (auto &attr : attributes) + check_attribute (attr); +} + +void +AttributeChecker::visit (AST::Token &tok) +{} + +void +AttributeChecker::visit (AST::DelimTokenTree &delim_tok_tree) +{} + +void +AttributeChecker::visit (AST::AttrInputMetaItemContainer &input) +{} + +void +AttributeChecker::visit (AST::IdentifierExpr &ident_expr) +{} + +void +AttributeChecker::visit (AST::Lifetime &lifetime) +{} + +void +AttributeChecker::visit (AST::LifetimeParam &lifetime_param) +{} + +void +AttributeChecker::visit (AST::ConstGenericParam &const_param) +{} + +// rust-path.h +void +AttributeChecker::visit (AST::PathInExpression &path) +{} + +void +AttributeChecker::visit (AST::TypePathSegment &segment) +{} + +void +AttributeChecker::visit (AST::TypePathSegmentGeneric &segment) +{} + +void +AttributeChecker::visit (AST::TypePathSegmentFunction &segment) +{} + +void +AttributeChecker::visit (AST::TypePath &path) +{} + +void +AttributeChecker::visit (AST::QualifiedPathInExpression &path) +{} + +void +AttributeChecker::visit (AST::QualifiedPathInType &path) +{} + +// rust-expr.h +void +AttributeChecker::visit (AST::LiteralExpr &expr) +{} + +void +AttributeChecker::visit (AST::AttrInputLiteral &attr_input) +{} + +void +AttributeChecker::visit (AST::MetaItemLitExpr &meta_item) +{} + +void +AttributeChecker::visit (AST::MetaItemPathLit &meta_item) +{} + +void +AttributeChecker::visit (AST::BorrowExpr &expr) +{} + +void +AttributeChecker::visit (AST::DereferenceExpr &expr) +{} + +void +AttributeChecker::visit (AST::ErrorPropagationExpr &expr) +{} + +void +AttributeChecker::visit (AST::NegationExpr &expr) +{} + +void +AttributeChecker::visit (AST::ArithmeticOrLogicalExpr &expr) +{} + +void +AttributeChecker::visit (AST::ComparisonExpr &expr) +{} + +void +AttributeChecker::visit (AST::LazyBooleanExpr &expr) +{} + +void +AttributeChecker::visit (AST::TypeCastExpr &expr) +{} + +void +AttributeChecker::visit (AST::AssignmentExpr &expr) +{} + +void +AttributeChecker::visit (AST::CompoundAssignmentExpr &expr) +{} + +void +AttributeChecker::visit (AST::GroupedExpr &expr) +{} + +void +AttributeChecker::visit (AST::ArrayElemsValues &elems) +{} + +void +AttributeChecker::visit (AST::ArrayElemsCopied &elems) +{} + +void +AttributeChecker::visit (AST::ArrayExpr &expr) +{} + +void +AttributeChecker::visit (AST::ArrayIndexExpr &expr) +{} + +void +AttributeChecker::visit (AST::TupleExpr &expr) +{} + +void +AttributeChecker::visit (AST::TupleIndexExpr &expr) +{} + +void +AttributeChecker::visit (AST::StructExprStruct &expr) +{} + +void +AttributeChecker::visit (AST::StructExprFieldIdentifier &field) +{} + +void +AttributeChecker::visit (AST::StructExprFieldIdentifierValue &field) +{} + +void +AttributeChecker::visit (AST::StructExprFieldIndexValue &field) +{} + +void +AttributeChecker::visit (AST::StructExprStructFields &expr) +{} + +void +AttributeChecker::visit (AST::StructExprStructBase &expr) +{} + +void +AttributeChecker::visit (AST::CallExpr &expr) +{} + +void +AttributeChecker::visit (AST::MethodCallExpr &expr) +{} + +void +AttributeChecker::visit (AST::FieldAccessExpr &expr) +{} + +void +AttributeChecker::visit (AST::ClosureExprInner &expr) +{} + +void +AttributeChecker::visit (AST::BlockExpr &expr) +{} + +void +AttributeChecker::visit (AST::ClosureExprInnerTyped &expr) +{} + +void +AttributeChecker::visit (AST::ContinueExpr &expr) +{} + +void +AttributeChecker::visit (AST::BreakExpr &expr) +{} + +void +AttributeChecker::visit (AST::RangeFromToExpr &expr) +{} + +void +AttributeChecker::visit (AST::RangeFromExpr &expr) +{} + +void +AttributeChecker::visit (AST::RangeToExpr &expr) +{} + +void +AttributeChecker::visit (AST::RangeFullExpr &expr) +{} + +void +AttributeChecker::visit (AST::RangeFromToInclExpr &expr) +{} + +void +AttributeChecker::visit (AST::RangeToInclExpr &expr) +{} + +void +AttributeChecker::visit (AST::ReturnExpr &expr) +{} + +void +AttributeChecker::visit (AST::UnsafeBlockExpr &expr) +{} + +void +AttributeChecker::visit (AST::LoopExpr &expr) +{} + +void +AttributeChecker::visit (AST::WhileLoopExpr &expr) +{} + +void +AttributeChecker::visit (AST::WhileLetLoopExpr &expr) +{} + +void +AttributeChecker::visit (AST::ForLoopExpr &expr) +{} + +void +AttributeChecker::visit (AST::IfExpr &expr) +{} + +void +AttributeChecker::visit (AST::IfExprConseqElse &expr) +{} + +void +AttributeChecker::visit (AST::IfExprConseqIf &expr) +{} + +void +AttributeChecker::visit (AST::IfExprConseqIfLet &expr) +{} + +void +AttributeChecker::visit (AST::IfLetExpr &expr) +{} + +void +AttributeChecker::visit (AST::IfLetExprConseqElse &expr) +{} + +void +AttributeChecker::visit (AST::IfLetExprConseqIf &expr) +{} + +void +AttributeChecker::visit (AST::IfLetExprConseqIfLet &expr) +{} + +void +AttributeChecker::visit (AST::MatchExpr &expr) +{} + +void +AttributeChecker::visit (AST::AwaitExpr &expr) +{} + +void +AttributeChecker::visit (AST::AsyncBlockExpr &expr) +{} + +// rust-item.h +void +AttributeChecker::visit (AST::TypeParam ¶m) +{} + +void +AttributeChecker::visit (AST::LifetimeWhereClauseItem &item) +{} + +void +AttributeChecker::visit (AST::TypeBoundWhereClauseItem &item) +{} + +void +AttributeChecker::visit (AST::Method &method) +{} + +void +AttributeChecker::visit (AST::Module &module) +{} + +void +AttributeChecker::visit (AST::ExternCrate &crate) +{} + +void +AttributeChecker::visit (AST::UseTreeGlob &use_tree) +{} + +void +AttributeChecker::visit (AST::UseTreeList &use_tree) +{} + +void +AttributeChecker::visit (AST::UseTreeRebind &use_tree) +{} + +void +AttributeChecker::visit (AST::UseDeclaration &use_decl) +{} + +void +AttributeChecker::visit (AST::Function &function) +{} + +void +AttributeChecker::visit (AST::TypeAlias &type_alias) +{} + +void +AttributeChecker::visit (AST::StructStruct &struct_item) +{ + check_attributes (struct_item.get_outer_attrs ()); +} + +void +AttributeChecker::visit (AST::TupleStruct &tuple_struct) +{} + +void +AttributeChecker::visit (AST::EnumItem &item) +{} + +void +AttributeChecker::visit (AST::EnumItemTuple &item) +{} + +void +AttributeChecker::visit (AST::EnumItemStruct &item) +{} + +void +AttributeChecker::visit (AST::EnumItemDiscriminant &item) +{} + +void +AttributeChecker::visit (AST::Enum &enum_item) +{} + +void +AttributeChecker::visit (AST::Union &union_item) +{} + +void +AttributeChecker::visit (AST::ConstantItem &const_item) +{} + +void +AttributeChecker::visit (AST::StaticItem &static_item) +{} + +void +AttributeChecker::visit (AST::TraitItemFunc &item) +{} + +void +AttributeChecker::visit (AST::TraitItemMethod &item) +{} + +void +AttributeChecker::visit (AST::TraitItemConst &item) +{} + +void +AttributeChecker::visit (AST::TraitItemType &item) +{} + +void +AttributeChecker::visit (AST::Trait &trait) +{} + +void +AttributeChecker::visit (AST::InherentImpl &impl) +{} + +void +AttributeChecker::visit (AST::TraitImpl &impl) +{} + +void +AttributeChecker::visit (AST::ExternalStaticItem &item) +{} + +void +AttributeChecker::visit (AST::ExternalFunctionItem &item) +{} + +void +AttributeChecker::visit (AST::ExternBlock &block) +{} + +// rust-macro.h +void +AttributeChecker::visit (AST::MacroMatchFragment &match) +{} + +void +AttributeChecker::visit (AST::MacroMatchRepetition &match) +{} + +void +AttributeChecker::visit (AST::MacroMatcher &matcher) +{} + +void +AttributeChecker::visit (AST::MacroRulesDefinition &rules_def) +{} + +void +AttributeChecker::visit (AST::MacroInvocation ¯o_invoc) +{} + +void +AttributeChecker::visit (AST::MetaItemPath &meta_item) +{} + +void +AttributeChecker::visit (AST::MetaItemSeq &meta_item) +{} + +void +AttributeChecker::visit (AST::MetaWord &meta_item) +{} + +void +AttributeChecker::visit (AST::MetaNameValueStr &meta_item) +{} + +void +AttributeChecker::visit (AST::MetaListPaths &meta_item) +{} + +void +AttributeChecker::visit (AST::MetaListNameValueStr &meta_item) +{} + +// rust-pattern.h +void +AttributeChecker::visit (AST::LiteralPattern &pattern) +{} + +void +AttributeChecker::visit (AST::IdentifierPattern &pattern) +{} + +void +AttributeChecker::visit (AST::WildcardPattern &pattern) +{} + +// void AttributeChecker::visit(RangePatternBound& bound){} + +void +AttributeChecker::visit (AST::RangePatternBoundLiteral &bound) +{} + +void +AttributeChecker::visit (AST::RangePatternBoundPath &bound) +{} + +void +AttributeChecker::visit (AST::RangePatternBoundQualPath &bound) +{} + +void +AttributeChecker::visit (AST::RangePattern &pattern) +{} + +void +AttributeChecker::visit (AST::ReferencePattern &pattern) +{} + +// void AttributeChecker::visit(StructPatternField& field){} + +void +AttributeChecker::visit (AST::StructPatternFieldTuplePat &field) +{} + +void +AttributeChecker::visit (AST::StructPatternFieldIdentPat &field) +{} + +void +AttributeChecker::visit (AST::StructPatternFieldIdent &field) +{} + +void +AttributeChecker::visit (AST::StructPattern &pattern) +{} + +// void AttributeChecker::visit(TupleStructItems& tuple_items){} + +void +AttributeChecker::visit (AST::TupleStructItemsNoRange &tuple_items) +{} + +void +AttributeChecker::visit (AST::TupleStructItemsRange &tuple_items) +{} + +void +AttributeChecker::visit (AST::TupleStructPattern &pattern) +{} + +// void AttributeChecker::visit(TuplePatternItems& tuple_items){} + +void +AttributeChecker::visit (AST::TuplePatternItemsMultiple &tuple_items) +{} + +void +AttributeChecker::visit (AST::TuplePatternItemsRanged &tuple_items) +{} + +void +AttributeChecker::visit (AST::TuplePattern &pattern) +{} + +void +AttributeChecker::visit (AST::GroupedPattern &pattern) +{} + +void +AttributeChecker::visit (AST::SlicePattern &pattern) +{} + +// rust-stmt.h +void +AttributeChecker::visit (AST::EmptyStmt &stmt) +{} + +void +AttributeChecker::visit (AST::LetStmt &stmt) +{} + +void +AttributeChecker::visit (AST::ExprStmtWithoutBlock &stmt) +{} + +void +AttributeChecker::visit (AST::ExprStmtWithBlock &stmt) +{} + +// rust-type.h +void +AttributeChecker::visit (AST::TraitBound &bound) +{} + +void +AttributeChecker::visit (AST::ImplTraitType &type) +{} + +void +AttributeChecker::visit (AST::TraitObjectType &type) +{} + +void +AttributeChecker::visit (AST::ParenthesisedType &type) +{} + +void +AttributeChecker::visit (AST::ImplTraitTypeOneBound &type) +{} + +void +AttributeChecker::visit (AST::TraitObjectTypeOneBound &type) +{} + +void +AttributeChecker::visit (AST::TupleType &type) +{} + +void +AttributeChecker::visit (AST::NeverType &type) +{} + +void +AttributeChecker::visit (AST::RawPointerType &type) +{} + +void +AttributeChecker::visit (AST::ReferenceType &type) +{} + +void +AttributeChecker::visit (AST::ArrayType &type) +{} + +void +AttributeChecker::visit (AST::SliceType &type) +{} + +void +AttributeChecker::visit (AST::InferredType &type) +{} + +void +AttributeChecker::visit (AST::BareFunctionType &type) +{} + +} // namespace Analysis +} // namespace Rust diff --git a/gcc/rust/util/rust-attributes.h b/gcc/rust/util/rust-attributes.h new file mode 100644 index 00000000000..3ac93ff5908 --- /dev/null +++ b/gcc/rust/util/rust-attributes.h @@ -0,0 +1,270 @@ +// 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 +// . + +#include "rust-ast.h" +#include "rust-system.h" +#include "rust-ast-visitor.h" + +namespace Rust { +namespace Analysis { + +enum CompilerPass +{ + UNKNOWN, + + EXPANSION, + NAME_RESOLUTION, + HIR_LOWERING, + TYPE_CHECK, + STATIC_ANALYSIS, + CODE_GENERATION +}; + +struct BuiltinAttrDefinition +{ + std::string name; + CompilerPass handler; + + static BuiltinAttrDefinition get_error () + { + return BuiltinAttrDefinition{"", UNKNOWN}; + } + + static BuiltinAttrDefinition &error_node () + { + static BuiltinAttrDefinition error_node = get_error (); + return error_node; + } + + bool is_error () const { return name.empty (); } +}; + +class BuiltinAttributeMappings +{ +public: + static BuiltinAttributeMappings *get (); + + const BuiltinAttrDefinition & + lookup_builtin (const std::string &attr_name) const; + +private: + BuiltinAttributeMappings (); + + std::map mappings; +}; + +/** + * Checks the validity of various attributes. The goal of this visitor is to + * make sure that attributes are applied in allowed contexts, for example to + * make sure that #[inline] is only applied to functions and closures, as well + * as checking the "arguments" or input given to these attributes, making sure + * it is appropriate and valid. + */ +class AttributeChecker : public AST::ASTVisitor +{ +public: + AttributeChecker (); + + /** + * Check all the attributes of all the items of a crate + */ + void go (AST::Crate &crate); + +private: + /* Check the validity of a given attribute */ + void check_attribute (const AST::Attribute &attribute); + + /* Check the validity of all given attributes */ + void check_attributes (const AST::AttrVec &attributes); + + // rust-ast.h + void visit (AST::Token &tok); + void visit (AST::DelimTokenTree &delim_tok_tree); + void visit (AST::AttrInputMetaItemContainer &input); + void visit (AST::IdentifierExpr &ident_expr); + void visit (AST::Lifetime &lifetime); + void visit (AST::LifetimeParam &lifetime_param); + void visit (AST::ConstGenericParam &const_param); + + // rust-path.h + void visit (AST::PathInExpression &path); + void visit (AST::TypePathSegment &segment); + void visit (AST::TypePathSegmentGeneric &segment); + void visit (AST::TypePathSegmentFunction &segment); + void visit (AST::TypePath &path); + void visit (AST::QualifiedPathInExpression &path); + void visit (AST::QualifiedPathInType &path); + + // rust-expr.h + void visit (AST::LiteralExpr &expr); + void visit (AST::AttrInputLiteral &attr_input); + void visit (AST::MetaItemLitExpr &meta_item); + void visit (AST::MetaItemPathLit &meta_item); + void visit (AST::BorrowExpr &expr); + void visit (AST::DereferenceExpr &expr); + void visit (AST::ErrorPropagationExpr &expr); + void visit (AST::NegationExpr &expr); + void visit (AST::ArithmeticOrLogicalExpr &expr); + void visit (AST::ComparisonExpr &expr); + void visit (AST::LazyBooleanExpr &expr); + void visit (AST::TypeCastExpr &expr); + void visit (AST::AssignmentExpr &expr); + void visit (AST::CompoundAssignmentExpr &expr); + void visit (AST::GroupedExpr &expr); + void visit (AST::ArrayElemsValues &elems); + void visit (AST::ArrayElemsCopied &elems); + void visit (AST::ArrayExpr &expr); + void visit (AST::ArrayIndexExpr &expr); + void visit (AST::TupleExpr &expr); + void visit (AST::TupleIndexExpr &expr); + void visit (AST::StructExprStruct &expr); + void visit (AST::StructExprFieldIdentifier &field); + void visit (AST::StructExprFieldIdentifierValue &field); + void visit (AST::StructExprFieldIndexValue &field); + void visit (AST::StructExprStructFields &expr); + void visit (AST::StructExprStructBase &expr); + void visit (AST::CallExpr &expr); + void visit (AST::MethodCallExpr &expr); + void visit (AST::FieldAccessExpr &expr); + void visit (AST::ClosureExprInner &expr); + void visit (AST::BlockExpr &expr); + void visit (AST::ClosureExprInnerTyped &expr); + void visit (AST::ContinueExpr &expr); + void visit (AST::BreakExpr &expr); + void visit (AST::RangeFromToExpr &expr); + void visit (AST::RangeFromExpr &expr); + void visit (AST::RangeToExpr &expr); + void visit (AST::RangeFullExpr &expr); + void visit (AST::RangeFromToInclExpr &expr); + void visit (AST::RangeToInclExpr &expr); + void visit (AST::ReturnExpr &expr); + void visit (AST::UnsafeBlockExpr &expr); + void visit (AST::LoopExpr &expr); + void visit (AST::WhileLoopExpr &expr); + void visit (AST::WhileLetLoopExpr &expr); + void visit (AST::ForLoopExpr &expr); + void visit (AST::IfExpr &expr); + void visit (AST::IfExprConseqElse &expr); + void visit (AST::IfExprConseqIf &expr); + void visit (AST::IfExprConseqIfLet &expr); + void visit (AST::IfLetExpr &expr); + void visit (AST::IfLetExprConseqElse &expr); + void visit (AST::IfLetExprConseqIf &expr); + void visit (AST::IfLetExprConseqIfLet &expr); + void visit (AST::MatchExpr &expr); + void visit (AST::AwaitExpr &expr); + void visit (AST::AsyncBlockExpr &expr); + + // rust-item.h + void visit (AST::TypeParam ¶m); + void visit (AST::LifetimeWhereClauseItem &item); + void visit (AST::TypeBoundWhereClauseItem &item); + void visit (AST::Method &method); + void visit (AST::Module &module); + void visit (AST::ExternCrate &crate); + void visit (AST::UseTreeGlob &use_tree); + void visit (AST::UseTreeList &use_tree); + void visit (AST::UseTreeRebind &use_tree); + void visit (AST::UseDeclaration &use_decl); + void visit (AST::Function &function); + void visit (AST::TypeAlias &type_alias); + void visit (AST::StructStruct &struct_item); + void visit (AST::TupleStruct &tuple_struct); + void visit (AST::EnumItem &item); + void visit (AST::EnumItemTuple &item); + void visit (AST::EnumItemStruct &item); + void visit (AST::EnumItemDiscriminant &item); + void visit (AST::Enum &enum_item); + void visit (AST::Union &union_item); + void visit (AST::ConstantItem &const_item); + void visit (AST::StaticItem &static_item); + void visit (AST::TraitItemFunc &item); + void visit (AST::TraitItemMethod &item); + void visit (AST::TraitItemConst &item); + void visit (AST::TraitItemType &item); + void visit (AST::Trait &trait); + void visit (AST::InherentImpl &impl); + void visit (AST::TraitImpl &impl); + void visit (AST::ExternalStaticItem &item); + void visit (AST::ExternalFunctionItem &item); + void visit (AST::ExternBlock &block); + + // rust-macro.h + void visit (AST::MacroMatchFragment &match); + void visit (AST::MacroMatchRepetition &match); + void visit (AST::MacroMatcher &matcher); + void visit (AST::MacroRulesDefinition &rules_def); + void visit (AST::MacroInvocation ¯o_invoc); + void visit (AST::MetaItemPath &meta_item); + void visit (AST::MetaItemSeq &meta_item); + void visit (AST::MetaWord &meta_item); + void visit (AST::MetaNameValueStr &meta_item); + void visit (AST::MetaListPaths &meta_item); + void visit (AST::MetaListNameValueStr &meta_item); + + // rust-pattern.h + void visit (AST::LiteralPattern &pattern); + void visit (AST::IdentifierPattern &pattern); + void visit (AST::WildcardPattern &pattern); + // void visit(RangePatternBound& bound); + void visit (AST::RangePatternBoundLiteral &bound); + void visit (AST::RangePatternBoundPath &bound); + void visit (AST::RangePatternBoundQualPath &bound); + void visit (AST::RangePattern &pattern); + void visit (AST::ReferencePattern &pattern); + // void visit(StructPatternField& field); + void visit (AST::StructPatternFieldTuplePat &field); + void visit (AST::StructPatternFieldIdentPat &field); + void visit (AST::StructPatternFieldIdent &field); + void visit (AST::StructPattern &pattern); + // void visit(TupleStructItems& tuple_items); + void visit (AST::TupleStructItemsNoRange &tuple_items); + void visit (AST::TupleStructItemsRange &tuple_items); + void visit (AST::TupleStructPattern &pattern); + // void visit(TuplePatternItems& tuple_items); + void visit (AST::TuplePatternItemsMultiple &tuple_items); + void visit (AST::TuplePatternItemsRanged &tuple_items); + void visit (AST::TuplePattern &pattern); + void visit (AST::GroupedPattern &pattern); + void visit (AST::SlicePattern &pattern); + + // rust-stmt.h + void visit (AST::EmptyStmt &stmt); + void visit (AST::LetStmt &stmt); + void visit (AST::ExprStmtWithoutBlock &stmt); + void visit (AST::ExprStmtWithBlock &stmt); + + // rust-type.h + void visit (AST::TraitBound &bound); + void visit (AST::ImplTraitType &type); + void visit (AST::TraitObjectType &type); + void visit (AST::ParenthesisedType &type); + void visit (AST::ImplTraitTypeOneBound &type); + void visit (AST::TraitObjectTypeOneBound &type); + void visit (AST::TupleType &type); + void visit (AST::NeverType &type); + void visit (AST::RawPointerType &type); + void visit (AST::ReferenceType &type); + void visit (AST::ArrayType &type); + void visit (AST::SliceType &type); + void visit (AST::InferredType &type); + void visit (AST::BareFunctionType &type); +}; + +} // namespace Analysis +} // namespace Rust From patchwork Wed Aug 24 11:59:40 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56998 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 0EF7A3935FCF for ; Wed, 24 Aug 2022 12:06:30 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x42f.google.com (mail-wr1-x42f.google.com [IPv6:2a00:1450:4864:20::42f]) by sourceware.org (Postfix) with ESMTPS id 506803898C66; Wed, 24 Aug 2022 12:01:00 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 506803898C66 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x42f.google.com with SMTP id b5so16204391wrr.5; Wed, 24 Aug 2022 05:01:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=a/jZdq1sr6ECjFK+Nj6bKluevEwVGkXtWwMrH40BFIU=; b=PK+0u3twVU85/T+pX/8TlISB1/1WrzuwOSrGmr5TTTzXLymupdQ6fhSBcNh8qcbkyL 6U+GPkF9jvdqwlvzqgY1xHnEPigjcJBmbiDpHsfw3KOEC57ADXX38hZTze9uIN6VKFAA T/JgiP/HJphPtDL920KKKMvWQlhCfKLBJm2yzw9DG2T7DJuAdFcYnkMbPjRzMkNzU+yd X9BU+t/Ir9YypJjLVBX+WPjty9ht4GalyN7M0V7N92havOuK0QpKEOTQxclKUr9oUi7m vPSg4BrUDTh83+LNspCiLPTtXrz83BVqaiqvgmCZ7uYfc7akD5giGsivUvcCMur69K8r gCqA== 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; bh=a/jZdq1sr6ECjFK+Nj6bKluevEwVGkXtWwMrH40BFIU=; b=avEFqkSoQeCMQR3i06lTwiRoq3Oju2cSqZZBtvamuuSKD2hb+siTHHhPgbD//dVA1m zMsxiNErUYWsAPwcLuxmj6goA5Mynejs6jKIbUwLUzFt2NmP44cqX64wOhkveNjTeRSD j12U34ULts/aU/wl9rrhFDrPzvasz2pVYOQ+5LAogjKcevBchRzEUtSZk03iwbEsmz6A 4i62w83PCk3aPRclMqC6v2m5o7+vkUHyJ/BBPGvnBK9xsCqNx3MYcdkH5yFhzSoJ2YUV Lr/iQUJHWDr+u31glD+WRSiOIRxqswK0Gpiri9nEnCnbhYgPFuOKvweIU/cOcvNZoy4z MGKg== X-Gm-Message-State: ACgBeo2bi36xfcATAv8DjDnKVa93w2FOiSGATO1qj0EcWcIBGSieFkJq xynIT3XZMnGPoPrPDtUjvyGTlPeRSG0= X-Google-Smtp-Source: AA6agR4F9R8MEepp5xIa5IXu2aWMdVFQRV7KlQ2MReUCCZdpBiwFpyRc/2dBzW8CAhOiOwHAh+H4zQ== X-Received: by 2002:adf:ce01:0:b0:225:2751:7654 with SMTP id p1-20020adfce01000000b0022527517654mr15856270wrn.220.1661342458730; Wed, 24 Aug 2022 05:00:58 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.00.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:00:57 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 21/37] gccrs: Add helpers mappings canonical path and lang items Date: Wed, 24 Aug 2022 12:59:40 +0100 Message-Id: <20220824115956.737931-22-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron These are various helper classes used in the compiler pipeline. --- gcc/rust/util/rust-canonical-path.h | 195 +++++ gcc/rust/util/rust-common.h | 53 ++ gcc/rust/util/rust-hir-map.cc | 980 ++++++++++++++++++++++++++ gcc/rust/util/rust-hir-map.h | 356 ++++++++++ gcc/rust/util/rust-identifier.h | 49 ++ gcc/rust/util/rust-lang-item.h | 377 ++++++++++ gcc/rust/util/rust-mapping-common.h | 85 +++ gcc/rust/util/rust-stacked-contexts.h | 86 +++ 8 files changed, 2181 insertions(+) create mode 100644 gcc/rust/util/rust-canonical-path.h create mode 100644 gcc/rust/util/rust-common.h create mode 100644 gcc/rust/util/rust-hir-map.cc create mode 100644 gcc/rust/util/rust-hir-map.h create mode 100644 gcc/rust/util/rust-identifier.h create mode 100644 gcc/rust/util/rust-lang-item.h create mode 100644 gcc/rust/util/rust-mapping-common.h create mode 100644 gcc/rust/util/rust-stacked-contexts.h diff --git a/gcc/rust/util/rust-canonical-path.h b/gcc/rust/util/rust-canonical-path.h new file mode 100644 index 00000000000..54cc0390849 --- /dev/null +++ b/gcc/rust/util/rust-canonical-path.h @@ -0,0 +1,195 @@ +// 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_CANONICAL_PATH +#define RUST_CANONICAL_PATH + +#include "rust-system.h" +#include "rust-mapping-common.h" + +namespace Rust { +namespace Resolver { + +// https://doc.rust-lang.org/reference/paths.html#canonical-paths +// +// struct X - path X +// impl X { fn test - path X::test } +// +// struct X - path X +// +// impl X { fn test - path X::test} +// impl X { fn test - path X::test } +// impl X { fn test - path X::test } +// +// pub trait Trait { // ::a::Trait +// fn f(&self); // ::a::Trait::f +// } +// +// impl Trait for Struct { +// fn f(&self) {} // <::a::Struct as ::a::Trait>::f +// } +class CanonicalPath +{ +public: + CanonicalPath (const CanonicalPath &other) : segs (other.segs) {} + + CanonicalPath &operator= (const CanonicalPath &other) + { + segs = other.segs; + return *this; + } + + static CanonicalPath new_seg (NodeId id, const std::string &path) + { + rust_assert (!path.empty ()); + return CanonicalPath ({std::pair (id, path)}, + UNKNOWN_CREATENUM); + } + + static CanonicalPath + trait_impl_projection_seg (NodeId id, const CanonicalPath &trait_seg, + const CanonicalPath &impl_type_seg) + { + return CanonicalPath::new_seg (id, "<" + impl_type_seg.get () + " as " + + trait_seg.get () + ">"); + } + + std::string get () const + { + std::string buf; + for (size_t i = 0; i < segs.size (); i++) + { + bool have_more = (i + 1) < segs.size (); + const std::string &seg = segs.at (i).second; + buf += seg + (have_more ? "::" : ""); + } + return buf; + } + + static CanonicalPath get_big_self (NodeId id) + { + return CanonicalPath::new_seg (id, "Self"); + } + + static CanonicalPath create_empty () + { + return CanonicalPath ({}, UNKNOWN_CREATENUM); + } + + bool is_empty () const { return segs.size () == 0; } + + CanonicalPath append (const CanonicalPath &other) const + { + rust_assert (!other.is_empty ()); + if (is_empty ()) + return CanonicalPath (other.segs, crate_num); + + std::vector> copy (segs); + for (auto &s : other.segs) + copy.push_back (s); + + return CanonicalPath (copy, crate_num); + } + + // if we have the path A::B::C this will give a callback for each segment + // including the prefix, example: + // + // path: + // A::B::C + // + // iterate: + // A + // A::B + // A::B::C + void iterate (std::function cb) const + { + std::vector> buf; + for (auto &seg : segs) + { + buf.push_back (seg); + if (!cb (CanonicalPath (buf, crate_num))) + return; + } + } + + // if we have the path A::B::C this will give a callback for each segment + // example: + // + // path: + // A::B::C + // + // iterate: + // A + // B + // C + void iterate_segs (std::function cb) const + { + for (auto &seg : segs) + { + std::vector> buf; + buf.push_back ({seg.first, seg.second}); + if (!cb (CanonicalPath (buf, crate_num))) + return; + } + } + + size_t size () const { return segs.size (); } + + NodeId get_node_id () const + { + rust_assert (!segs.empty ()); + return segs.back ().first; + } + + const std::pair &get_seg_at (size_t index) const + { + rust_assert (index < size ()); + return segs.at (index); + } + + bool is_equal (const CanonicalPath &b) const + { + return get ().compare (b.get ()) == 0; + } + + void set_crate_num (CrateNum n) { crate_num = n; } + + CrateNum get_crate_num () const + { + rust_assert (crate_num != UNKNOWN_CREATENUM); + return crate_num; + } + + bool operator== (const CanonicalPath &b) const { return is_equal (b); } + + bool operator< (const CanonicalPath &b) const { return get () < b.get (); } + +private: + explicit CanonicalPath (std::vector> path, + CrateNum crate_num) + : segs (path), crate_num (crate_num) + {} + + std::vector> segs; + CrateNum crate_num; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_CANONICAL_PATH diff --git a/gcc/rust/util/rust-common.h b/gcc/rust/util/rust-common.h new file mode 100644 index 00000000000..a3f6fb07d8d --- /dev/null +++ b/gcc/rust/util/rust-common.h @@ -0,0 +1,53 @@ +// Copyright (C) 2021-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 +// . + +// Common definitions useful throughout the Rust frontend. + +#ifndef RUST_COMMON +#define RUST_COMMON + +namespace Rust { + +enum Mutability +{ + Imm, + Mut +}; + +enum Unsafety +{ + Unsafe, + Normal +}; + +enum Polarity +{ + Positive, + Negative +}; + +enum AsyncConstStatus +{ + NONE, + CONST_FN, + ASYNC_FN +}; + +} // namespace Rust + +#endif // RUST_COMMON diff --git a/gcc/rust/util/rust-hir-map.cc b/gcc/rust/util/rust-hir-map.cc new file mode 100644 index 00000000000..8705fdcf381 --- /dev/null +++ b/gcc/rust/util/rust-hir-map.cc @@ -0,0 +1,980 @@ +// 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 +// . + +#include "rust-hir-map.h" +#include "rust-ast-full.h" +#include "rust-diagnostics.h" +#include "rust-hir-full.h" +#include "rust-macro-builtins.h" +#include "rust-mapping-common.h" + +namespace Rust { +namespace Analysis { + +NodeMapping +NodeMapping::get_error () +{ + return NodeMapping (UNKNOWN_CREATENUM, UNKNOWN_NODEID, UNKNOWN_HIRID, + UNKNOWN_LOCAL_DEFID); +} + +CrateNum +NodeMapping::get_crate_num () const +{ + return crateNum; +} + +NodeId +NodeMapping::get_nodeid () const +{ + return nodeId; +} + +HirId +NodeMapping::get_hirid () const +{ + return hirId; +} + +LocalDefId +NodeMapping::get_local_defid () const +{ + return localDefId; +} + +DefId +NodeMapping::get_defid () const +{ + return get_defid (get_crate_num (), get_local_defid ()); +} + +DefId +NodeMapping::get_defid (CrateNum crate_num, LocalDefId local_defid) +{ + return DefId{crate_num, local_defid}; +} + +std::string +NodeMapping::as_string () const +{ + std::ostringstream ss; + ss << "[" + << "C: " << get_crate_num (); + if (get_nodeid () != UNKNOWN_NODEID) + ss << " Nid: " << get_nodeid (); + + if (get_hirid () != UNKNOWN_HIRID) + ss << " Hid: " << get_hirid (); + + if (get_local_defid () != UNKNOWN_LOCAL_DEFID) + ss << " Lid: " << get_local_defid (); + + ss << "]"; + return ss.str (); +} + +// Mappings Class now +static const HirId kDefaultNodeIdBegin = 1; +static const HirId kDefaultHirIdBegin = 1; +static const HirId kDefaultCrateNumBegin = 0; + +Mappings::Mappings () + : crateNumItr (kDefaultCrateNumBegin), currentCrateNum (UNKNOWN_CREATENUM), + hirIdIter (kDefaultHirIdBegin), nodeIdIter (kDefaultNodeIdBegin) +{} + +Mappings::~Mappings () {} + +Mappings * +Mappings::get () +{ + static std::unique_ptr instance; + if (!instance) + instance = std::unique_ptr (new Mappings ()); + + return instance.get (); +} + +CrateNum +Mappings::get_next_crate_num (const std::string &name) +{ + auto id = crateNumItr; + crateNumItr++; + set_crate_name (id, name); + return id; +} + +void +Mappings::set_current_crate (CrateNum crateNum) +{ + currentCrateNum = crateNum; +} + +CrateNum +Mappings::get_current_crate () const +{ + return currentCrateNum; +} + +bool +Mappings::get_crate_name (CrateNum crate_num, std::string &name) const +{ + auto it = crate_names.find (crate_num); + if (it == crate_names.end ()) + return false; + + name.assign (it->second); + return true; +} + +void +Mappings::set_crate_name (CrateNum crate_num, const std::string &name) +{ + crate_names[crate_num] = name; +} + +std::string +Mappings::get_current_crate_name () const +{ + std::string name; + bool ok = get_crate_name (get_current_crate (), name); + rust_assert (ok); + return name; +} + +bool +Mappings::lookup_crate_name (const std::string &crate_name, + CrateNum &resolved_crate_num) const +{ + for (const auto &it : crate_names) + { + if (it.second.compare (crate_name) == 0) + { + resolved_crate_num = it.first; + return true; + } + } + return false; +} + +bool +Mappings::crate_num_to_nodeid (const CrateNum &crate_num, NodeId &node_id) const +{ + auto it = ast_crate_mappings.find (crate_num); + if (it == ast_crate_mappings.end ()) + return false; + + node_id = it->second->get_node_id (); + return true; +} + +bool +Mappings::node_is_crate (NodeId node_id) const +{ + for (const auto &it : ast_crate_mappings) + { + NodeId crate_node_id = it.second->get_node_id (); + if (crate_node_id == node_id) + return true; + } + return false; +} + +NodeId +Mappings::get_next_node_id () +{ + auto it = nodeIdIter; + nodeIdIter++; + return it; +} + +HirId +Mappings::get_next_hir_id (CrateNum crateNum) +{ + auto id = hirIdIter; + hirIdIter++; + + auto it = hirNodesWithinCrate.find (crateNum); + if (it == hirNodesWithinCrate.end ()) + { + hirNodesWithinCrate.insert ({crateNum, {}}); + } + + hirNodesWithinCrate[crateNum].insert (id); + return id; +} + +LocalDefId +Mappings::get_next_localdef_id (CrateNum crateNum) +{ + auto it = localIdIter.find (crateNum); + if (it == localIdIter.end ()) + { + localIdIter.insert ({crateNum, 1}); + } + + it = localIdIter.find (crateNum); + rust_assert (it != localIdIter.end ()); + + LocalDefId id = it->second; + localIdIter[crateNum] = id + 1; + return id; +} + +AST::Crate & +Mappings::get_ast_crate (CrateNum crateNum) +{ + auto it = ast_crate_mappings.find (crateNum); + rust_assert (it != ast_crate_mappings.end ()); + return *it->second; +} + +AST::Crate & +Mappings::get_ast_crate_by_node_id (NodeId id) +{ + auto i = crate_node_to_crate_num.find (id); + rust_assert (i != crate_node_to_crate_num.end ()); + + CrateNum crateNum = i->second; + auto it = ast_crate_mappings.find (crateNum); + rust_assert (it != ast_crate_mappings.end ()); + return *it->second; +} + +AST::Crate & +Mappings::insert_ast_crate (std::unique_ptr &&crate, + CrateNum crate_num) +{ + auto it = ast_crate_mappings.find (crate_num); + rust_assert (it == ast_crate_mappings.end ()); + + // store it + ast_crate_mappings.insert ({crate_num, crate.release ()}); + + // return the reference to it + it = ast_crate_mappings.find (crate_num); + rust_assert (it != ast_crate_mappings.end ()); + return *it->second; +} + +HIR::Crate & +Mappings::get_hir_crate (CrateNum crateNum) +{ + auto it = hir_crate_mappings.find (crateNum); + rust_assert (it != hir_crate_mappings.end ()); + return *it->second; +} + +bool +Mappings::is_local_hirid_crate (HirId crateNum) +{ + for (const auto &it : hir_crate_mappings) + { + const auto &crate = it.second; + if (crate->get_mappings ().get_hirid () == crateNum) + return true; + } + return false; +} + +HIR::Crate & +Mappings::insert_hir_crate (std::unique_ptr &&crate) +{ + CrateNum crateNum = crate->get_mappings ().get_crate_num (); + auto it = hir_crate_mappings.find (crateNum); + rust_assert (it == hir_crate_mappings.end ()); + + insert_node_to_hir (crate->get_mappings ().get_nodeid (), + crate->get_mappings ().get_hirid ()); + hir_crate_mappings.insert ({crateNum, crate.release ()}); + + it = hir_crate_mappings.find (crateNum); + rust_assert (it != hir_crate_mappings.end ()); + return *it->second; +} + +void +Mappings::insert_defid_mapping (DefId id, HIR::Item *item) +{ + CrateNum crate_num = id.crateNum; + LocalDefId local_def_id = id.localDefId; + + rust_assert (lookup_defid (id) == nullptr); + rust_assert (lookup_local_defid (crate_num, local_def_id) == nullptr); + + defIdMappings[id] = item; + insert_local_defid_mapping (crate_num, local_def_id, item); +} + +HIR::Item * +Mappings::lookup_defid (DefId id) +{ + auto it = defIdMappings.find (id); + if (it == defIdMappings.end ()) + return nullptr; + + return it->second; +} + +void +Mappings::insert_hir_item (HIR::Item *item) +{ + auto id = item->get_mappings ().get_hirid (); + rust_assert (lookup_hir_item (id) == nullptr); + + hirItemMappings[id] = item; + insert_node_to_hir (item->get_mappings ().get_nodeid (), id); +} + +HIR::Item * +Mappings::lookup_hir_item (HirId id) +{ + auto it = hirItemMappings.find (id); + if (it == hirItemMappings.end ()) + return nullptr; + + return it->second; +} + +void +Mappings::insert_hir_trait_item (HIR::TraitItem *item) +{ + auto id = item->get_mappings ().get_hirid (); + rust_assert (lookup_hir_trait_item (id) == nullptr); + + hirTraitItemMappings[id] = item; + insert_node_to_hir (item->get_mappings ().get_nodeid (), id); +} + +HIR::TraitItem * +Mappings::lookup_hir_trait_item (HirId id) +{ + auto it = hirTraitItemMappings.find (id); + if (it == hirTraitItemMappings.end ()) + return nullptr; + + return it->second; +} + +void +Mappings::insert_hir_extern_block (HIR::ExternBlock *block) +{ + auto id = block->get_mappings ().get_hirid (); + rust_assert (lookup_hir_extern_block (id) == nullptr); + + hirExternBlockMappings[id] = block; + insert_node_to_hir (block->get_mappings ().get_nodeid (), id); +} + +HIR::ExternBlock * +Mappings::lookup_hir_extern_block (HirId id) +{ + auto it = hirExternBlockMappings.find (id); + if (it == hirExternBlockMappings.end ()) + return nullptr; + + return it->second; +} + +void +Mappings::insert_hir_extern_item (HIR::ExternalItem *item, HirId parent_block) +{ + auto id = item->get_mappings ().get_hirid (); + rust_assert (lookup_hir_extern_item (id, nullptr) == nullptr); + + hirExternItemMappings[id] = {item, parent_block}; + insert_node_to_hir (item->get_mappings ().get_nodeid (), id); +} + +HIR::ExternalItem * +Mappings::lookup_hir_extern_item (HirId id, HirId *parent_block) +{ + auto it = hirExternItemMappings.find (id); + if (it == hirExternItemMappings.end ()) + return nullptr; + + *parent_block = it->second.second; + + return it->second.first; +} + +void +Mappings::insert_hir_impl_block (HIR::ImplBlock *item) +{ + auto id = item->get_mappings ().get_hirid (); + rust_assert (lookup_hir_impl_block (id) == nullptr); + + hirImplBlockMappings[id] = item; + insert_node_to_hir (item->get_mappings ().get_nodeid (), id); +} + +HIR::ImplBlock * +Mappings::lookup_hir_impl_block (HirId id) +{ + auto it = hirImplBlockMappings.find (id); + if (it == hirImplBlockMappings.end ()) + return nullptr; + + return it->second; +} + +void +Mappings::insert_module (HIR::Module *module) +{ + auto id = module->get_mappings ().get_hirid (); + rust_assert (lookup_module (id) == nullptr); + + hirModuleMappings[id] = module; + insert_node_to_hir (module->get_mappings ().get_nodeid (), id); +} + +HIR::Module * +Mappings::lookup_module (HirId id) +{ + auto it = hirModuleMappings.find (id); + if (it == hirModuleMappings.end ()) + return nullptr; + + return it->second; +} + +void +Mappings::insert_hir_implitem (HirId parent_impl_id, HIR::ImplItem *item) +{ + auto id = item->get_impl_mappings ().get_hirid (); + rust_assert (lookup_hir_implitem (id, nullptr) == nullptr); + + hirImplItemMappings[id] + = std::pair (parent_impl_id, item); + insert_node_to_hir (item->get_impl_mappings ().get_nodeid (), id); +} + +HIR::ImplItem * +Mappings::lookup_hir_implitem (HirId id, HirId *parent_impl_id) +{ + auto it = hirImplItemMappings.find (id); + if (it == hirImplItemMappings.end ()) + return nullptr; + + std::pair &ref = it->second; + if (parent_impl_id != nullptr) + *parent_impl_id = ref.first; + + return ref.second; +} + +void +Mappings::insert_hir_expr (HIR::Expr *expr) +{ + auto id = expr->get_mappings ().get_hirid (); + hirExprMappings[id] = expr; + + insert_node_to_hir (expr->get_mappings ().get_nodeid (), id); + insert_location (id, expr->get_locus ()); +} + +HIR::Expr * +Mappings::lookup_hir_expr (HirId id) +{ + auto it = hirExprMappings.find (id); + if (it == hirExprMappings.end ()) + return nullptr; + + return it->second; +} + +void +Mappings::insert_hir_path_expr_seg (HIR::PathExprSegment *expr) +{ + auto id = expr->get_mappings ().get_hirid (); + rust_assert (lookup_hir_path_expr_seg (id) == nullptr); + + hirPathSegMappings[id] = expr; + insert_node_to_hir (expr->get_mappings ().get_nodeid (), id); + insert_location (id, expr->get_locus ()); +} + +HIR::PathExprSegment * +Mappings::lookup_hir_path_expr_seg (HirId id) +{ + auto it = hirPathSegMappings.find (id); + if (it == hirPathSegMappings.end ()) + return nullptr; + + return it->second; +} + +void +Mappings::insert_hir_generic_param (HIR::GenericParam *param) +{ + auto id = param->get_mappings ().get_hirid (); + rust_assert (lookup_hir_generic_param (id) == nullptr); + + hirGenericParamMappings[id] = param; + insert_node_to_hir (param->get_mappings ().get_nodeid (), id); + insert_location (id, param->get_locus ()); +} + +HIR::GenericParam * +Mappings::lookup_hir_generic_param (HirId id) +{ + auto it = hirGenericParamMappings.find (id); + if (it == hirGenericParamMappings.end ()) + return nullptr; + + return it->second; +} + +void +Mappings::insert_hir_type (HIR::Type *type) +{ + auto id = type->get_mappings ().get_hirid (); + rust_assert (lookup_hir_type (id) == nullptr); + + hirTypeMappings[id] = type; + insert_node_to_hir (type->get_mappings ().get_nodeid (), id); +} + +HIR::Type * +Mappings::lookup_hir_type (HirId id) +{ + auto it = hirTypeMappings.find (id); + if (it == hirTypeMappings.end ()) + return nullptr; + + return it->second; +} + +void +Mappings::insert_hir_stmt (HIR::Stmt *stmt) +{ + auto id = stmt->get_mappings ().get_hirid (); + rust_assert (lookup_hir_stmt (id) == nullptr); + + hirStmtMappings[id] = stmt; + insert_node_to_hir (stmt->get_mappings ().get_nodeid (), id); +} + +HIR::Stmt * +Mappings::lookup_hir_stmt (HirId id) +{ + auto it = hirStmtMappings.find (id); + if (it == hirStmtMappings.end ()) + return nullptr; + + return it->second; +} + +void +Mappings::insert_hir_param (HIR::FunctionParam *param) +{ + auto id = param->get_mappings ().get_hirid (); + rust_assert (lookup_hir_param (id) == nullptr); + + hirParamMappings[id] = param; + insert_node_to_hir (param->get_mappings ().get_nodeid (), id); +} + +HIR::FunctionParam * +Mappings::lookup_hir_param (HirId id) +{ + auto it = hirParamMappings.find (id); + if (it == hirParamMappings.end ()) + return nullptr; + + return it->second; +} + +void +Mappings::insert_hir_self_param (HIR::SelfParam *param) +{ + auto id = param->get_mappings ().get_hirid (); + rust_assert (lookup_hir_self_param (id) == nullptr); + + hirSelfParamMappings[id] = param; + insert_node_to_hir (param->get_mappings ().get_nodeid (), id); +} + +HIR::SelfParam * +Mappings::lookup_hir_self_param (HirId id) +{ + auto it = hirSelfParamMappings.find (id); + if (it == hirSelfParamMappings.end ()) + return nullptr; + + return it->second; +} + +void +Mappings::insert_hir_struct_field (HIR::StructExprField *field) +{ + auto id = field->get_mappings ().get_hirid (); + rust_assert (lookup_hir_struct_field (id) == nullptr); + + hirStructFieldMappings[id] = field; + insert_node_to_hir (field->get_mappings ().get_nodeid (), id); +} + +HIR::StructExprField * +Mappings::lookup_hir_struct_field (HirId id) +{ + auto it = hirStructFieldMappings.find (id); + if (it == hirStructFieldMappings.end ()) + return nullptr; + + return it->second; +} + +void +Mappings::insert_hir_pattern (HIR::Pattern *pattern) +{ + auto id = pattern->get_pattern_mappings ().get_hirid (); + rust_assert (lookup_hir_pattern (id) == nullptr); + + hirPatternMappings[id] = pattern; + insert_node_to_hir (pattern->get_pattern_mappings ().get_nodeid (), id); +} + +HIR::Pattern * +Mappings::lookup_hir_pattern (HirId id) +{ + auto it = hirPatternMappings.find (id); + if (it == hirPatternMappings.end ()) + return nullptr; + + return it->second; +} + +void +Mappings::insert_local_defid_mapping (CrateNum crateNum, LocalDefId id, + HIR::Item *item) +{ + rust_assert (lookup_local_defid (crateNum, id) == nullptr); + localDefIdMappings[crateNum][id] = item; +} + +HIR::Item * +Mappings::lookup_local_defid (CrateNum crateNum, LocalDefId id) +{ + auto it = localDefIdMappings.find (crateNum); + if (it == localDefIdMappings.end ()) + return nullptr; + + auto iy = it->second.find (id); + if (iy == it->second.end ()) + return nullptr; + + return iy->second; +} + +void +Mappings::walk_local_defids_for_crate (CrateNum crateNum, + std::function cb) +{ + auto it = localDefIdMappings.find (crateNum); + if (it == localDefIdMappings.end ()) + return; + + for (auto iy = it->second.begin (); iy != it->second.end (); iy++) + { + if (!cb (iy->second)) + return; + } +} + +void +Mappings::insert_node_to_hir (NodeId id, HirId ref) +{ + nodeIdToHirMappings[id] = ref; + hirIdToNodeMappings[ref] = id; +} + +bool +Mappings::lookup_node_to_hir (NodeId id, HirId *ref) +{ + auto it = nodeIdToHirMappings.find (id); + if (it == nodeIdToHirMappings.end ()) + return false; + + *ref = it->second; + return true; +} + +bool +Mappings::lookup_hir_to_node (HirId id, NodeId *ref) +{ + auto it = hirIdToNodeMappings.find (id); + if (it == hirIdToNodeMappings.end ()) + return false; + + *ref = it->second; + return true; +} + +void +Mappings::insert_location (HirId id, Location locus) +{ + locations[id] = locus; +} + +Location +Mappings::lookup_location (HirId id) +{ + auto it = locations.find (id); + if (it == locations.end ()) + return Location (); + + return it->second; +} + +bool +Mappings::resolve_nodeid_to_stmt (NodeId id, HIR::Stmt **stmt) +{ + auto it = nodeIdToHirMappings.find (id); + if (it == nodeIdToHirMappings.end ()) + return false; + + HirId resolved = it->second; + auto resolved_stmt = lookup_hir_stmt (resolved); + *stmt = resolved_stmt; + return resolved_stmt != nullptr; +} + +void +Mappings::iterate_impl_items ( + std::function cb) +{ + for (auto it = hirImplItemMappings.begin (); it != hirImplItemMappings.end (); + it++) + { + auto id = it->first; + auto impl_item = it->second.second; + auto impl + = lookup_associated_impl (impl_item->get_impl_mappings ().get_hirid ()); + if (!cb (id, impl_item, impl)) + return; + } +} + +void +Mappings::iterate_impl_blocks (std::function cb) +{ + for (auto it = hirImplBlockMappings.begin (); + it != hirImplBlockMappings.end (); it++) + { + HirId id = it->first; + HIR::ImplBlock *impl_block = it->second; + if (!cb (id, impl_block)) + return; + } +} + +void +Mappings::iterate_trait_items ( + std::function cb) +{ + for (auto it = hirTraitItemMappings.begin (); + it != hirTraitItemMappings.end (); it++) + { + HirId trait_item_id = it->first; + HIR::TraitItem *trait_item = it->second; + HIR::Trait *trait = lookup_trait_item_mapping (trait_item_id); + + if (!cb (trait_item, trait)) + return; + } +} + +void +Mappings::insert_macro_def (AST::MacroRulesDefinition *macro) +{ + static std::map> + builtin_macros = { + {"assert", MacroBuiltin::assert}, + {"file", MacroBuiltin::file}, + {"line", MacroBuiltin::line}, + {"column", MacroBuiltin::column}, + {"include_bytes", MacroBuiltin::include_bytes}, + {"include_str", MacroBuiltin::include_str}, + {"compile_error", MacroBuiltin::compile_error}, + {"concat", MacroBuiltin::concat}, + {"env", MacroBuiltin::env}, + {"cfg", MacroBuiltin::cfg}, + {"include", MacroBuiltin::include}, + }; + + auto outer_attrs = macro->get_outer_attrs (); + bool should_be_builtin + = std::any_of (outer_attrs.begin (), outer_attrs.end (), + [] (AST::Attribute attr) { + return attr.get_path () == "rustc_builtin_macro"; + }); + if (should_be_builtin) + { + auto builtin = builtin_macros.find (macro->get_rule_name ()); + if (builtin != builtin_macros.end ()) + macro->set_builtin_transcriber (builtin->second); + else + rust_error_at (macro->get_locus (), + "cannot find a built-in macro with name %qs", + macro->get_rule_name ().c_str ()); + } + + auto it = macroMappings.find (macro->get_node_id ()); + rust_assert (it == macroMappings.end ()); + + macroMappings[macro->get_node_id ()] = macro; +} + +bool +Mappings::lookup_macro_def (NodeId id, AST::MacroRulesDefinition **def) +{ + auto it = macroMappings.find (id); + if (it == macroMappings.end ()) + return false; + + *def = it->second; + return true; +} + +void +Mappings::insert_visibility (NodeId id, Privacy::ModuleVisibility visibility) +{ + visibility_map.insert ({id, visibility}); +} + +bool +Mappings::lookup_visibility (NodeId id, Privacy::ModuleVisibility &def) +{ + auto it = visibility_map.find (id); + if (it == visibility_map.end ()) + return false; + + def = it->second; + return true; +} + +void +Mappings::insert_module_child (NodeId module, NodeId child) +{ + auto it = module_child_map.find (module); + if (it == module_child_map.end ()) + module_child_map.insert ({module, {child}}); + else + it->second.emplace_back (child); +} + +Optional &> +Mappings::lookup_module_children (NodeId module) +{ + auto it = module_child_map.find (module); + if (it == module_child_map.end ()) + return Optional &>::none (); + + return Optional &>::some (it->second); +} + +void +Mappings::insert_module_child_item (NodeId module, + Resolver::CanonicalPath child) +{ + rust_assert (!child.is_empty ()); + rust_assert (child.get_node_id () != UNKNOWN_NODEID); + + auto it = module_child_items.find (module); + if (it == module_child_items.end ()) + module_child_items.insert ({module, {child}}); + else + it->second.emplace_back (child); +} + +Optional &> +Mappings::lookup_module_chidren_items (NodeId module) +{ + auto it = module_child_items.find (module); + if (it == module_child_items.end ()) + return Optional &>::none (); + + return Optional &>::some (it->second); +} + +Optional +Mappings::lookup_module_child (NodeId module, const std::string &item_name) +{ + Optional &> children + = lookup_module_chidren_items (module); + if (children.is_none ()) + return Optional::none (); + + // lookup the children to match the name if we can + for (auto &child : children.get ()) + { + const std::string &raw_identifier = child.get (); + bool found = raw_identifier.compare (item_name) == 0; + if (found) + return Optional::some (child); + } + return Optional::none (); +} + +void +Mappings::insert_child_item_to_parent_module_mapping (NodeId child_item, + NodeId parent_module) +{ + child_to_parent_module_map.insert ({child_item, parent_module}); +} + +Optional +Mappings::lookup_parent_module (NodeId child_item) +{ + auto it = child_to_parent_module_map.find (child_item); + if (it == child_to_parent_module_map.end ()) + return Optional::none (); + + return Optional::some (it->second); +} + +bool +Mappings::node_is_module (NodeId query) +{ + return module_child_items.find (query) != module_child_items.end (); +} + +void +Mappings::insert_ast_item (AST::Item *item) +{ + auto it = ast_item_mappings.find (item->get_node_id ()); + rust_assert (it == ast_item_mappings.end ()); + + ast_item_mappings[item->get_node_id ()] = item; +} + +bool +Mappings::lookup_ast_item (NodeId id, AST::Item **result) +{ + auto it = ast_item_mappings.find (id); + if (it == ast_item_mappings.end ()) + return false; + + *result = it->second; + return true; +} + +} // namespace Analysis +} // namespace Rust diff --git a/gcc/rust/util/rust-hir-map.h b/gcc/rust/util/rust-hir-map.h new file mode 100644 index 00000000000..98fcfe6a6a7 --- /dev/null +++ b/gcc/rust/util/rust-hir-map.h @@ -0,0 +1,356 @@ +// 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_HIR_MAP_H +#define RUST_HIR_MAP_H + +#include "rust-optional.h" +#include "rust-system.h" +#include "rust-location.h" +#include "rust-mapping-common.h" +#include "rust-canonical-path.h" +#include "rust-ast-full-decls.h" +#include "rust-hir-full-decls.h" +#include "rust-lang-item.h" +#include "rust-privacy-common.h" + +namespace Rust { +namespace Analysis { + +class NodeMapping +{ +public: + NodeMapping (CrateNum crateNum, NodeId nodeId, HirId hirId, + LocalDefId localDefId) + : crateNum (crateNum), nodeId (nodeId), hirId (hirId), + localDefId (localDefId) + {} + + static NodeMapping get_error (); + + CrateNum get_crate_num () const; + NodeId get_nodeid () const; + HirId get_hirid () const; + LocalDefId get_local_defid () const; + DefId get_defid () const; + + static DefId get_defid (CrateNum crate_num, LocalDefId local_defid); + + std::string as_string () const; + + bool is_equal (const NodeMapping &other) const + { + return get_crate_num () == other.get_crate_num () + && get_nodeid () == other.get_nodeid () + && get_hirid () == other.get_hirid () + && get_local_defid () == other.get_local_defid (); + } + +private: + CrateNum crateNum; + NodeId nodeId; + HirId hirId; + LocalDefId localDefId; +}; + +class Mappings +{ +public: + static Mappings *get (); + ~Mappings (); + + CrateNum get_next_crate_num (const std::string &name); + void set_current_crate (CrateNum crateNum); + CrateNum get_current_crate () const; + bool get_crate_name (CrateNum crate_num, std::string &name) const; + void set_crate_name (CrateNum crate_num, const std::string &name); + std::string get_current_crate_name () const; + bool lookup_crate_name (const std::string &crate_name, + CrateNum &resolved_crate_num) const; + bool crate_num_to_nodeid (const CrateNum &crate_num, NodeId &node_id) const; + bool node_is_crate (NodeId node_id) const; + + NodeId get_next_node_id (); + HirId get_next_hir_id () { return get_next_hir_id (get_current_crate ()); } + HirId get_next_hir_id (CrateNum crateNum); + LocalDefId get_next_localdef_id () + { + return get_next_localdef_id (get_current_crate ()); + } + LocalDefId get_next_localdef_id (CrateNum crateNum); + + AST::Crate &get_ast_crate (CrateNum crateNum); + AST::Crate &get_ast_crate_by_node_id (NodeId id); + AST::Crate &insert_ast_crate (std::unique_ptr &&crate, + CrateNum crate_num); + HIR::Crate &insert_hir_crate (std::unique_ptr &&crate); + HIR::Crate &get_hir_crate (CrateNum crateNum); + bool is_local_hirid_crate (HirId crateNum); + + void insert_defid_mapping (DefId id, HIR::Item *item); + HIR::Item *lookup_defid (DefId id); + + void insert_local_defid_mapping (CrateNum crateNum, LocalDefId id, + HIR::Item *item); + HIR::Item *lookup_local_defid (CrateNum crateNum, LocalDefId id); + + void insert_hir_item (HIR::Item *item); + HIR::Item *lookup_hir_item (HirId id); + + void insert_hir_trait_item (HIR::TraitItem *item); + HIR::TraitItem *lookup_hir_trait_item (HirId id); + + void insert_hir_extern_block (HIR::ExternBlock *block); + HIR::ExternBlock *lookup_hir_extern_block (HirId id); + + void insert_hir_extern_item (HIR::ExternalItem *item, HirId parent_block); + HIR::ExternalItem *lookup_hir_extern_item (HirId id, HirId *parent_block); + + void insert_hir_impl_block (HIR::ImplBlock *item); + HIR::ImplBlock *lookup_hir_impl_block (HirId id); + + void insert_module (HIR::Module *module); + HIR::Module *lookup_module (HirId id); + + void insert_hir_implitem (HirId parent_impl_id, HIR::ImplItem *item); + HIR::ImplItem *lookup_hir_implitem (HirId id, HirId *parent_impl_id); + + void insert_hir_expr (HIR::Expr *expr); + HIR::Expr *lookup_hir_expr (HirId id); + + void insert_hir_path_expr_seg (HIR::PathExprSegment *expr); + HIR::PathExprSegment *lookup_hir_path_expr_seg (HirId id); + + void insert_hir_generic_param (HIR::GenericParam *expr); + HIR::GenericParam *lookup_hir_generic_param (HirId id); + + void insert_hir_type (HIR::Type *type); + HIR::Type *lookup_hir_type (HirId id); + + void insert_hir_stmt (HIR::Stmt *stmt); + HIR::Stmt *lookup_hir_stmt (HirId id); + + void insert_hir_param (HIR::FunctionParam *type); + HIR::FunctionParam *lookup_hir_param (HirId id); + + void insert_hir_self_param (HIR::SelfParam *type); + HIR::SelfParam *lookup_hir_self_param (HirId id); + + void insert_hir_struct_field (HIR::StructExprField *type); + HIR::StructExprField *lookup_hir_struct_field (HirId id); + + void insert_hir_pattern (HIR::Pattern *pattern); + HIR::Pattern *lookup_hir_pattern (HirId id); + + void walk_local_defids_for_crate (CrateNum crateNum, + std::function cb); + + void insert_node_to_hir (NodeId id, HirId ref); + bool lookup_node_to_hir (NodeId id, HirId *ref); + bool lookup_hir_to_node (HirId id, NodeId *ref); + + void insert_location (HirId id, Location locus); + Location lookup_location (HirId id); + + bool resolve_nodeid_to_stmt (NodeId id, HIR::Stmt **stmt); + + std::set &get_hirids_within_crate (CrateNum crate) + { + return hirNodesWithinCrate[crate]; + } + + void insert_impl_item_mapping (HirId impl_item_id, HIR::ImplBlock *impl) + { + rust_assert (hirImplItemsToImplMappings.find (impl_item_id) + == hirImplItemsToImplMappings.end ()); + hirImplItemsToImplMappings[impl_item_id] = impl; + } + + HIR::ImplBlock *lookup_associated_impl (HirId impl_item_id) + { + auto lookup = hirImplItemsToImplMappings.find (impl_item_id); + rust_assert (lookup != hirImplItemsToImplMappings.end ()); + return lookup->second; + } + + void iterate_impl_items ( + std::function cb); + + void iterate_impl_blocks (std::function cb); + + void iterate_trait_items ( + std::function cb); + + bool is_impl_item (HirId id) + { + HirId parent_impl_block_id = UNKNOWN_HIRID; + return lookup_hir_implitem (id, &parent_impl_block_id) != nullptr; + } + + void insert_trait_item_mapping (HirId trait_item_id, HIR::Trait *trait) + { + rust_assert (hirTraitItemsToTraitMappings.find (trait_item_id) + == hirTraitItemsToTraitMappings.end ()); + hirTraitItemsToTraitMappings[trait_item_id] = trait; + } + + HIR::Trait *lookup_trait_item_mapping (HirId trait_item_id) + { + auto lookup = hirTraitItemsToTraitMappings.find (trait_item_id); + rust_assert (lookup != hirTraitItemsToTraitMappings.end ()); + return lookup->second; + } + + void insert_canonical_path (NodeId id, const Resolver::CanonicalPath path) + { + const Resolver::CanonicalPath *p = nullptr; + if (lookup_canonical_path (id, &p)) + { + // if we have already stored a canonical path this is ok so long as + // this new path is equal or is smaller that the existing one but in + // that case we ignore it. + if (p->is_equal (path)) + return; + else + { + rust_assert (p->size () >= path.size ()); + return; + } + } + + paths.emplace (id, std::move (path)); + } + + bool lookup_canonical_path (NodeId id, const Resolver::CanonicalPath **path) + { + auto it = paths.find (id); + if (it == paths.end ()) + return false; + + *path = &it->second; + return true; + } + + void insert_lang_item (RustLangItem::ItemType item_type, DefId id) + { + auto it = lang_item_mappings.find (item_type); + rust_assert (it == lang_item_mappings.end ()); + + lang_item_mappings[item_type] = id; + } + + bool lookup_lang_item (RustLangItem::ItemType item_type, DefId *id) + { + auto it = lang_item_mappings.find (item_type); + if (it == lang_item_mappings.end ()) + return false; + + *id = it->second; + return true; + } + + void insert_macro_def (AST::MacroRulesDefinition *macro); + + bool lookup_macro_def (NodeId id, AST::MacroRulesDefinition **def); + + void insert_visibility (NodeId id, Privacy::ModuleVisibility visibility); + bool lookup_visibility (NodeId id, Privacy::ModuleVisibility &def); + + void insert_module_child (NodeId module, NodeId child); + Optional &> lookup_module_children (NodeId module); + + void insert_module_child_item (NodeId module, Resolver::CanonicalPath item); + Optional &> + lookup_module_chidren_items (NodeId module); + Optional + lookup_module_child (NodeId module, const std::string &item_name); + + void insert_child_item_to_parent_module_mapping (NodeId child_item, + NodeId parent_module); + Optional lookup_parent_module (NodeId child_item); + bool node_is_module (NodeId query); + + void insert_ast_item (AST::Item *item); + bool lookup_ast_item (NodeId id, AST::Item **result); + +private: + Mappings (); + + CrateNum crateNumItr; + CrateNum currentCrateNum; + HirId hirIdIter; + NodeId nodeIdIter; + std::map localIdIter; + + std::map crate_node_to_crate_num; + std::map ast_crate_mappings; + std::map hir_crate_mappings; + std::map defIdMappings; + std::map> localDefIdMappings; + + std::map hirModuleMappings; + std::map hirItemMappings; + std::map hirTypeMappings; + std::map hirExprMappings; + std::map hirStmtMappings; + std::map hirParamMappings; + std::map hirStructFieldMappings; + std::map> hirImplItemMappings; + std::map hirSelfParamMappings; + std::map hirImplItemsToImplMappings; + std::map hirImplBlockMappings; + std::map hirTraitItemMappings; + std::map hirExternBlockMappings; + std::map> hirExternItemMappings; + std::map hirPathSegMappings; + std::map hirGenericParamMappings; + std::map hirTraitItemsToTraitMappings; + std::map hirPatternMappings; + std::map lang_item_mappings; + std::map paths; + std::map locations; + std::map nodeIdToHirMappings; + std::map hirIdToNodeMappings; + + // all hirid nodes + std::map> hirNodesWithinCrate; + + // macros + std::map macroMappings; + + // crate names + std::map crate_names; + + // Low level visibility map for each DefId + std::map visibility_map; + + // Module tree maps + + // Maps each module's node id to a list of its children + std::map> module_child_map; + std::map> module_child_items; + std::map child_to_parent_module_map; + + // AST mappings + std::map ast_item_mappings; +}; + +} // namespace Analysis +} // namespace Rust + +#endif // RUST_HIR_MAP_H diff --git a/gcc/rust/util/rust-identifier.h b/gcc/rust/util/rust-identifier.h new file mode 100644 index 00000000000..0b5cb70b373 --- /dev/null +++ b/gcc/rust/util/rust-identifier.h @@ -0,0 +1,49 @@ +// 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_IDENTIFIER +#define RUST_IDENTIFIER + +#include "rust-canonical-path.h" +#include "rust-location.h" + +namespace Rust { + +struct RustIdent +{ + Resolver::CanonicalPath path; + Location locus; + + RustIdent (const Resolver::CanonicalPath &path, Location locus) + : path (path), locus (locus) + {} + + RustIdent (const RustIdent &other) : path (other.path), locus (other.locus) {} + + RustIdent &operator= (const RustIdent &other) + { + path = other.path; + locus = other.locus; + + return *this; + } +}; + +} // namespace Rust + +#endif // RUST_IDENTIFIER diff --git a/gcc/rust/util/rust-lang-item.h b/gcc/rust/util/rust-lang-item.h new file mode 100644 index 00000000000..9d1ee900aec --- /dev/null +++ b/gcc/rust/util/rust-lang-item.h @@ -0,0 +1,377 @@ +// 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 +// . + +#include "rust-system.h" +#include "operator.h" + +namespace Rust { +namespace Analysis { + +// https://github.com/rust-lang/rust/blob/master/library/core/src/ops/arith.rs +class RustLangItem +{ +public: + enum ItemType + { + ADD, + SUBTRACT, + MULTIPLY, + DIVIDE, + REMAINDER, + BITAND, + BITOR, + BITXOR, + SHL, + SHR, + + NEGATION, + NOT, + + ADD_ASSIGN, + SUB_ASSIGN, + MUL_ASSIGN, + DIV_ASSIGN, + REM_ASSIGN, + BITAND_ASSIGN, + BITOR_ASSIGN, + BITXOR_ASSIGN, + SHL_ASSIGN, + SHR_ASSIGN, + + DEREF, + DEREF_MUT, + + // https://github.com/rust-lang/rust/blob/master/library/core/src/ops/index.rs + INDEX, + INDEX_MUT, + + // https://github.com/rust-lang/rust/blob/master/library/core/src/ops/range.rs + RANGE_FULL, + RANGE, + RANGE_FROM, + RANGE_TO, + RANGE_INCLUSIVE, + RANGE_TO_INCLUSIVE, + + // https://github.com/rust-lang/rust/blob/master/library/core/src/ptr/const_ptr.rs + CONST_PTR, + MUT_PTR, + CONST_SLICE_PTR, + + UNKNOWN, + }; + + static ItemType Parse (const std::string &item) + { + if (item.compare ("add") == 0) + { + return ItemType::ADD; + } + else if (item.compare ("sub") == 0) + { + return ItemType::SUBTRACT; + } + else if (item.compare ("mul") == 0) + { + return ItemType::MULTIPLY; + } + else if (item.compare ("div") == 0) + { + return ItemType::DIVIDE; + } + else if (item.compare ("rem") == 0) + { + return ItemType::REMAINDER; + } + else if (item.compare ("bitand") == 0) + { + return ItemType::BITAND; + } + else if (item.compare ("bitor") == 0) + { + return ItemType::BITOR; + } + else if (item.compare ("bitxor") == 0) + { + return ItemType::BITXOR; + } + else if (item.compare ("shl") == 0) + { + return ItemType::SHL; + } + else if (item.compare ("shr") == 0) + { + return ItemType::SHR; + } + else if (item.compare ("neg") == 0) + { + return ItemType::NEGATION; + } + else if (item.compare ("not") == 0) + { + return ItemType::NOT; + } + else if (item.compare ("add_assign") == 0) + { + return ItemType::ADD_ASSIGN; + } + else if (item.compare ("sub_assign") == 0) + { + return ItemType::SUB_ASSIGN; + } + else if (item.compare ("mul_assign") == 0) + { + return ItemType::MUL_ASSIGN; + } + else if (item.compare ("div_assign") == 0) + { + return ItemType::DIV_ASSIGN; + } + else if (item.compare ("rem_assign") == 0) + { + return ItemType::REM_ASSIGN; + } + else if (item.compare ("bitand_assign") == 0) + { + return ItemType::BITAND_ASSIGN; + } + else if (item.compare ("bitor_assign") == 0) + { + return ItemType::BITOR_ASSIGN; + } + else if (item.compare ("bitxor_assign") == 0) + { + return ItemType::BITXOR_ASSIGN; + } + else if (item.compare ("shl_assign") == 0) + { + return ItemType::SHL_ASSIGN; + } + else if (item.compare ("shr_assign") == 0) + { + return ItemType::SHR_ASSIGN; + } + else if (item.compare ("deref") == 0) + { + return ItemType::DEREF; + } + else if (item.compare ("deref_mut") == 0) + { + return ItemType::DEREF_MUT; + } + else if (item.compare ("index") == 0) + { + return ItemType::INDEX; + } + else if (item.compare ("index_mut") == 0) + { + return ItemType::INDEX_MUT; + } + else if (item.compare ("RangeFull") == 0) + { + return ItemType::RANGE_FULL; + } + else if (item.compare ("Range") == 0) + { + return ItemType::RANGE; + } + else if (item.compare ("RangeFrom") == 0) + { + return ItemType::RANGE_FROM; + } + else if (item.compare ("RangeTo") == 0) + { + return ItemType::RANGE_TO; + } + else if (item.compare ("RangeInclusive") == 0) + { + return ItemType::RANGE_INCLUSIVE; + } + else if (item.compare ("RangeToInclusive") == 0) + { + return ItemType::RANGE_TO_INCLUSIVE; + } + else if (item.compare ("const_ptr") == 0) + { + return ItemType::CONST_PTR; + } + else if (item.compare ("mut_ptr") == 0) + { + return ItemType::MUT_PTR; + } + else if (item.compare ("const_slice_ptr") == 0) + { + return ItemType::CONST_SLICE_PTR; + } + + return ItemType::UNKNOWN; + } + + static std::string ToString (ItemType type) + { + switch (type) + { + case ADD: + return "add"; + case SUBTRACT: + return "sub"; + case MULTIPLY: + return "mul"; + case DIVIDE: + return "div"; + case REMAINDER: + return "rem"; + case BITAND: + return "bitand"; + case BITOR: + return "bitor"; + case BITXOR: + return "bitxor"; + case SHL: + return "shl"; + case SHR: + return "shr"; + case NEGATION: + return "neg"; + case NOT: + return "not"; + case ADD_ASSIGN: + return "add_assign"; + case SUB_ASSIGN: + return "sub_assign"; + case MUL_ASSIGN: + return "mul_assign"; + case DIV_ASSIGN: + return "div_assign"; + case REM_ASSIGN: + return "rem_assign"; + case BITAND_ASSIGN: + return "bitand_assign"; + case BITOR_ASSIGN: + return "bitor_assign"; + case BITXOR_ASSIGN: + return "bitxor_assign"; + case SHL_ASSIGN: + return "shl_assign"; + case SHR_ASSIGN: + return "shr_assign"; + case DEREF: + return "deref"; + case DEREF_MUT: + return "deref_mut"; + case INDEX: + return "index"; + case INDEX_MUT: + return "index_mut"; + case RANGE_FULL: + return "RangeFull"; + case RANGE: + return "Range"; + case RANGE_FROM: + return "RangeFrom"; + case RANGE_TO: + return "RangeTo"; + case RANGE_INCLUSIVE: + return "RangeInclusive"; + case RANGE_TO_INCLUSIVE: + return "RangeToInclusive"; + case CONST_PTR: + return "const_ptr"; + case MUT_PTR: + return "mut_ptr"; + case CONST_SLICE_PTR: + return "const_slice_ptr"; + + case UNKNOWN: + return ""; + } + return ""; + } + + static ItemType OperatorToLangItem (ArithmeticOrLogicalOperator op) + { + switch (op) + { + case ArithmeticOrLogicalOperator::ADD: + return ItemType::ADD; + case ArithmeticOrLogicalOperator::SUBTRACT: + return ItemType::SUBTRACT; + case ArithmeticOrLogicalOperator::MULTIPLY: + return ItemType::MULTIPLY; + case ArithmeticOrLogicalOperator::DIVIDE: + return ItemType::DIVIDE; + case ArithmeticOrLogicalOperator::MODULUS: + return ItemType::REMAINDER; + case ArithmeticOrLogicalOperator::BITWISE_AND: + return ItemType::BITAND; + case ArithmeticOrLogicalOperator::BITWISE_OR: + return ItemType::BITOR; + case ArithmeticOrLogicalOperator::BITWISE_XOR: + return ItemType::BITXOR; + case ArithmeticOrLogicalOperator::LEFT_SHIFT: + return ItemType::SHL; + case ArithmeticOrLogicalOperator::RIGHT_SHIFT: + return ItemType::SHR; + } + return ItemType::UNKNOWN; + } + + static ItemType + CompoundAssignmentOperatorToLangItem (ArithmeticOrLogicalOperator op) + { + switch (op) + { + case ArithmeticOrLogicalOperator::ADD: + return ItemType::ADD_ASSIGN; + case ArithmeticOrLogicalOperator::SUBTRACT: + return ItemType::SUB_ASSIGN; + case ArithmeticOrLogicalOperator::MULTIPLY: + return ItemType::MUL_ASSIGN; + case ArithmeticOrLogicalOperator::DIVIDE: + return ItemType::DIV_ASSIGN; + case ArithmeticOrLogicalOperator::MODULUS: + return ItemType::REM_ASSIGN; + case ArithmeticOrLogicalOperator::BITWISE_AND: + return ItemType::BITAND_ASSIGN; + case ArithmeticOrLogicalOperator::BITWISE_OR: + return ItemType::BITOR_ASSIGN; + case ArithmeticOrLogicalOperator::BITWISE_XOR: + return ItemType::BITXOR_ASSIGN; + case ArithmeticOrLogicalOperator::LEFT_SHIFT: + return ItemType::SHL_ASSIGN; + case ArithmeticOrLogicalOperator::RIGHT_SHIFT: + return ItemType::SHR_ASSIGN; + } + return ItemType::UNKNOWN; + } + + static ItemType NegationOperatorToLangItem (NegationOperator op) + { + switch (op) + { + case NegationOperator::NEGATE: + return ItemType::NEGATION; + case NegationOperator::NOT: + return ItemType::NOT; + } + return ItemType::UNKNOWN; + } +}; + +} // namespace Analysis +} // namespace Rust diff --git a/gcc/rust/util/rust-mapping-common.h b/gcc/rust/util/rust-mapping-common.h new file mode 100644 index 00000000000..c440ae98931 --- /dev/null +++ b/gcc/rust/util/rust-mapping-common.h @@ -0,0 +1,85 @@ +// 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_MAPPING_COMMON +#define RUST_MAPPING_COMMON + +#include "rust-system.h" + +namespace Rust { + +// refers to a Crate +typedef uint32_t CrateNum; +// refers to any node in the AST in current Crate +typedef uint32_t NodeId; +// refers to any node in the HIR for the current crate +typedef uint32_t HirId; +// refers to any top-level decl in HIR +typedef uint32_t LocalDefId; + +struct DefId +{ + CrateNum crateNum; + LocalDefId localDefId; + + bool operator== (const DefId &other) const + { + return this->crateNum == other.crateNum + && this->localDefId == other.localDefId; + } + + bool operator!= (const DefId &other) const { return !(*this == other); } + + bool operator< (const DefId &other) const + { + return ((uint64_t) this->crateNum << 32 | this->localDefId) + < ((uint64_t) other.crateNum << 32 | other.localDefId); + } + + std::string as_string () const + { + std::string buf; + buf += std::to_string (crateNum); + buf += " "; // or anything else + buf += std::to_string (localDefId); + return buf; + } +}; + +#define UNKNOWN_CREATENUM ((uint32_t) (0)) +#define UNKNOWN_NODEID ((uint32_t) (0)) +#define UNKNOWN_HIRID ((uint32_t) (0)) +#define UNKNOWN_LOCAL_DEFID ((uint32_t) (0)) +#define UNKNOWN_DEFID (DefId{0, 0}) + +} // namespace Rust + +namespace std { +template <> struct hash +{ + size_t operator() (const Rust::DefId &id) const noexcept + { + // TODO: Check if we can improve performance by having a better hash + // algorithm for `DefId`s + return hash () (hash () (id.crateNum) + + hash () (id.localDefId)); + } +}; +} // namespace std + +#endif // RUST_MAPPING_COMMON diff --git a/gcc/rust/util/rust-stacked-contexts.h b/gcc/rust/util/rust-stacked-contexts.h new file mode 100644 index 00000000000..c34eb907f06 --- /dev/null +++ b/gcc/rust/util/rust-stacked-contexts.h @@ -0,0 +1,86 @@ +// 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_CONTEXT_STACK_H +#define RUST_CONTEXT_STACK_H + +#include "rust-system.h" + +namespace Rust { + +/** + * Context stack util class. This class is useful for situations where you can + * enter the same kind of context multiple times. For example, when dealing with + * unsafe contexts, you might be tempted to simply keep a boolean value. + * + * ```rust + * let a = 15; + * unsafe { // we set the boolean to true + * // Now unsafe operations are allowed! + * let b = *(&a as *const i32); + * let c = std::mem::transmute(b); // Urgh! + * } // we set it to false + * ``` + * + * However, since the language allows nested unsafe blocks, you may run into + * this situation: + * + * ```rust + * unsafe { // we set the boolean to true + * unsafe { // we set the boolean to true + * } // we set it to false + * + * // Now unsafe operations are forbidden again, the boolean is false + * let f = std::mem::transmute(15); // Error! + * } // we set it to false + * ``` + */ +template class StackedContexts +{ +public: + /** + * Enter a special context + */ + void enter (T value) { stack.emplace_back (value); } + + /** + * Exit a special context + */ + T exit () + { + rust_assert (!stack.empty ()); + + auto last = stack.back (); + stack.pop_back (); + + return last; + } + + /** + * Are we currently inside of a special context? + */ + bool is_in_context () const { return !stack.empty (); } + +private: + /* Actual data */ + std::vector stack; +}; + +} // namespace Rust + +#endif /* !RUST_CONTEXT_STACK_H */ From patchwork Wed Aug 24 11:59:42 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56997 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 8A67E383163B for ; Wed, 24 Aug 2022 12:06:00 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com [IPv6:2a00:1450:4864:20::42e]) by sourceware.org (Postfix) with ESMTPS id 2C01F38983A5; Wed, 24 Aug 2022 12:01:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 2C01F38983A5 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x42e.google.com with SMTP id h5so19678471wru.7; Wed, 24 Aug 2022 05:01:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=cSpqYU1D9ItlltcLfcZWUikLm3ec3eLEHuEHj/0XdMM=; b=hzK1OSM9eOHsalI+eblxgXxW7rjOtnaXeyn2cuZapGYrr2j0CG7aRnVEfsvnehAtKu uL/kzRA1Za301yo8YtOctgMxiVUlTWacY3sLlpCk11apWq8UeNHs2w0ow8sLx+Rb5lJo Wsfcv7XLttFQnYE/IgEc2mfXJRviRNUtdm74Makqm3UJVxmR4XDZxxtGnee2mNAu4Zsf YpvF8Nbhf56bkyD9ft8p14uSyEkzQAYzDb7gvXWhJLEjK+LQ4IRcCn46+JKH8CYKXjhN rHF/tJQybWghT22G3w31eLceDZVfT4m+1Ki3wNUVEA2o0qKLRMmVbimxnh4jd+YZGivY twiw== 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; bh=cSpqYU1D9ItlltcLfcZWUikLm3ec3eLEHuEHj/0XdMM=; b=vji5X/h92Yh8vGeboGsOimYkoYod9oJJDj6fSdDE0y3umTgtJaZktMv5qBvU54K9rB n1x1eyqsIYvwP80xgt0p/g+BvTwv3m6itr94r3yIxtxt3+qoCh5lya3iVAjsxoNUj0uU TNM2VazjrC7Q/fqhAK/NPpWTJEuykFD3fXgWhH2uLdAijZ0t1kYaKQwv4cJuFNWi5tPi HHryQRwL/DYmbkEdnsDTC97Of1MTJUrR+zXT/ANYUctvNbfGF0/uEx7elBIcb7hKTmQK HJ3JDXqfE1d41tDeMy8gzd37186cYbQTPipJFWWZy919N0MU1KLMnXVlu5OPg28t0fPj fxKA== X-Gm-Message-State: ACgBeo152wyimFFwhNEwPspF00fsA/TV3RuN2zM86YTeduEv4jjnKvTC knOmjuBRZ7+Mcd3hMZtJk0M46LXBHOo= X-Google-Smtp-Source: AA6agR5wgW8sKY1XtKq8ahN0EAQGOS3KYCNnYUTbQdQgjtfZmX2iTTv2Fb7PpuaW4hQkbvRGsIIJFg== X-Received: by 2002:a05:6000:2a9:b0:225:7388:ad75 with SMTP id l9-20020a05600002a900b002257388ad75mr1041427wry.240.1661342463117; Wed, 24 Aug 2022 05:01:03 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.01.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:01:02 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 23/37] gccrs: Add unsafe checks for Rust Date: Wed, 24 Aug 2022 12:59:42 +0100 Message-Id: <20220824115956.737931-24-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: Arthur Cohen , gcc-rust@gcc.gnu.org Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Arthur Cohen The UnsafeChecker visitor verifies that unsafe actions are only performed in unsafe contexts. Otherwise, an error should be reported to the user and the compilation pipeline should be halted. These contexts, which include unsafe blocks or unsafe functions, are allowed to perform more actions than regular safe Rust code. These actions currently include: - Dereferencing raw pointers - Calls to unsafe functions - Use of inline assembly - Use of mutable static - Use of extern static - Access to a union's field - Call to functions with #[target(feature)] attribute - Initializing type with rustc_layout_scalar_valid_range attribute - Mutation of layout constrained field - Borrow of layout constrained field --- gcc/rust/checks/errors/rust-unsafe-checker.cc | 963 ++++++++++++++++++ gcc/rust/checks/errors/rust-unsafe-checker.h | 191 ++++ 2 files changed, 1154 insertions(+) create mode 100644 gcc/rust/checks/errors/rust-unsafe-checker.cc create mode 100644 gcc/rust/checks/errors/rust-unsafe-checker.h diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc b/gcc/rust/checks/errors/rust-unsafe-checker.cc new file mode 100644 index 00000000000..e3f32539562 --- /dev/null +++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc @@ -0,0 +1,963 @@ +// 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 +// . + +#include "rust-unsafe-checker.h" +#include "rust-hir.h" +#include "rust-hir-expr.h" +#include "rust-hir-stmt.h" +#include "rust-hir-item.h" + +namespace Rust { +namespace HIR { + +UnsafeChecker::UnsafeChecker () + : context (*Resolver::TypeCheckContext::get ()), + resolver (*Resolver::Resolver::get ()), + mappings (*Analysis::Mappings::get ()) +{} + +void +UnsafeChecker::go (HIR::Crate &crate) +{ + for (auto &item : crate.items) + item->accept_vis (*this); +} + +static void +check_static_mut (HIR::Item *maybe_static, Location locus) +{ + if (maybe_static->get_hir_kind () == Node::BaseKind::VIS_ITEM) + { + auto item = static_cast (maybe_static); + if (item->get_item_kind () == Item::ItemKind::Static) + { + auto static_item = static_cast (item); + if (static_item->is_mut ()) + rust_error_at ( + locus, "use of mutable static requires unsafe function or block"); + } + } +} + +static void +check_extern_static (HIR::ExternalItem *maybe_static, Location locus) +{ + if (maybe_static->get_extern_kind () == ExternalItem::ExternKind::Static) + rust_error_at (locus, + "use of extern static requires unsafe function or block"); +} + +void +UnsafeChecker::check_use_of_static (HirId node_id, Location locus) +{ + if (unsafe_context.is_in_context ()) + return; + + auto maybe_static_mut = mappings.lookup_hir_item (node_id); + + HirId extern_block; + auto maybe_extern_static + = mappings.lookup_hir_extern_item (node_id, &extern_block); + + if (maybe_static_mut) + check_static_mut (maybe_static_mut, locus); + + if (maybe_extern_static) + check_extern_static (static_cast (maybe_extern_static), + locus); +} + +static void +check_unsafe_call (HIR::Function *fn, Location locus, const std::string &kind) +{ + if (fn->get_qualifiers ().is_unsafe ()) + rust_error_at (locus, "call to unsafe %s requires unsafe function or block", + kind.c_str ()); +} + +static bool +is_safe_intrinsic (const std::string &fn_name) +{ + static const std::unordered_set safe_intrinsics = { + "abort", + "size_of", + "min_align_of", + "needs_drop", + "caller_location", + "add_with_overflow", + "sub_with_overflow", + "mul_with_overflow", + "wrapping_add", + "wrapping_sub", + "wrapping_mul", + "saturating_add", + "saturating_sub", + "rotate_left", + "rotate_right", + "ctpop", + "ctlz", + "cttz", + "bswap", + "bitreverse", + "discriminant_value", + "type_id", + "likely", + "unlikely", + "ptr_guaranteed_eq", + "ptr_guaranteed_ne", + "minnumf32", + "minnumf64", + "maxnumf32", + "rustc_peek", + "maxnumf64", + "type_name", + "forget", + "black_box", + "variant_count", + }; + + return safe_intrinsics.find (fn_name) != safe_intrinsics.end (); +} + +static void +check_extern_call (HIR::ExternalItem *maybe_fn, HIR::ExternBlock *parent_block, + Location locus) +{ + // We have multiple operations to perform here + // 1. Is the item an actual function we're calling + // 2. Is the block it's defined in an FFI block or an `extern crate` block + // + // It is not unsafe to call into other crates, so items defined in an `extern + // crate` must be callable without being in an unsafe context. On the other + // hand, any function defined in a block with a specific ABI (even `extern + // "Rust"` blocks) is unsafe to call + + if (maybe_fn->get_extern_kind () != ExternalItem::ExternKind::Function) + return; + + // Some intrinsics are safe to call + if (parent_block->get_abi () == Rust::ABI::INTRINSIC + && is_safe_intrinsic (maybe_fn->get_item_name ())) + return; + + rust_error_at (locus, + "call to extern function requires unsafe function or block"); +} + +void +UnsafeChecker::check_function_call (HirId node_id, Location locus) +{ + if (unsafe_context.is_in_context ()) + return; + + HirId parent_extern_block; + auto maybe_fn = mappings.lookup_hir_item (node_id); + auto maybe_extern + = mappings.lookup_hir_extern_item (node_id, &parent_extern_block); + + if (maybe_fn && maybe_fn->get_item_kind () == Item::ItemKind::Function) + check_unsafe_call (static_cast (maybe_fn), locus, "function"); + + if (maybe_extern) + check_extern_call (static_cast (maybe_extern), + mappings.lookup_hir_extern_block (parent_extern_block), + locus); +} + +void +UnsafeChecker::visit (Lifetime &lifetime) +{} + +void +UnsafeChecker::visit (LifetimeParam &lifetime_param) +{} + +void +UnsafeChecker::visit (PathInExpression &path) +{ + NodeId ast_node_id = path.get_mappings ().get_nodeid (); + NodeId ref_node_id; + HirId definition_id; + + if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) + return; + + rust_assert (mappings.lookup_node_to_hir (ref_node_id, &definition_id)); + + check_use_of_static (definition_id, path.get_locus ()); +} + +void +UnsafeChecker::visit (TypePathSegment &segment) +{} + +void +UnsafeChecker::visit (TypePathSegmentGeneric &segment) +{} + +void +UnsafeChecker::visit (TypePathSegmentFunction &segment) +{} + +void +UnsafeChecker::visit (TypePath &path) +{} + +void +UnsafeChecker::visit (QualifiedPathInExpression &path) +{} + +void +UnsafeChecker::visit (QualifiedPathInType &path) +{} + +void +UnsafeChecker::visit (LiteralExpr &expr) +{} + +void +UnsafeChecker::visit (BorrowExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (DereferenceExpr &expr) +{ + TyTy::BaseType *to_deref_type; + auto to_deref = expr.get_expr ()->get_mappings ().get_hirid (); + + rust_assert (context.lookup_type (to_deref, &to_deref_type)); + + if (to_deref_type->get_kind () == TyTy::TypeKind::POINTER + && !unsafe_context.is_in_context ()) + rust_error_at (expr.get_locus (), "dereference of raw pointer requires " + "unsafe function or block"); +} + +void +UnsafeChecker::visit (ErrorPropagationExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (NegationExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (ArithmeticOrLogicalExpr &expr) +{ + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (ComparisonExpr &expr) +{ + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (LazyBooleanExpr &expr) +{ + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (TypeCastExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (AssignmentExpr &expr) +{ + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (CompoundAssignmentExpr &expr) +{ + expr.get_left_expr ()->accept_vis (*this); + expr.get_right_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (GroupedExpr &expr) +{ + expr.get_expr_in_parens ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (ArrayElemsValues &elems) +{ + for (auto &elem : elems.get_values ()) + elem->accept_vis (*this); +} + +void +UnsafeChecker::visit (ArrayElemsCopied &elems) +{ + elems.get_elem_to_copy ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (ArrayExpr &expr) +{ + expr.get_internal_elements ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (ArrayIndexExpr &expr) +{ + expr.get_array_expr ()->accept_vis (*this); + expr.get_index_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (TupleExpr &expr) +{ + for (auto &elem : expr.get_tuple_elems ()) + elem->accept_vis (*this); +} + +void +UnsafeChecker::visit (TupleIndexExpr &expr) +{ + expr.get_tuple_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (StructExprStruct &expr) +{} + +void +UnsafeChecker::visit (StructExprFieldIdentifier &field) +{} + +void +UnsafeChecker::visit (StructExprFieldIdentifierValue &field) +{ + field.get_value ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (StructExprFieldIndexValue &field) +{ + field.get_value ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (StructExprStructFields &expr) +{ + for (auto &field : expr.get_fields ()) + field->accept_vis (*this); +} + +void +UnsafeChecker::visit (StructExprStructBase &expr) +{} + +void +UnsafeChecker::visit (CallExpr &expr) +{ + auto fn = expr.get_fnexpr (); + if (!fn) + return; + + NodeId ast_node_id = fn->get_mappings ().get_nodeid (); + NodeId ref_node_id; + HirId definition_id; + + // There are no unsafe types, and functions are defined in the name resolver. + // If we can't find the name, then we're dealing with a type and should return + // early. + if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) + return; + + rust_assert (mappings.lookup_node_to_hir (ref_node_id, &definition_id)); + + // At this point we have the function's HIR Id. There are two checks we + // must perform: + // 1. The function is an unsafe one + // 2. The function is an extern one + check_function_call (definition_id, expr.get_locus ()); + + if (expr.has_params ()) + for (auto &arg : expr.get_arguments ()) + arg->accept_vis (*this); +} + +void +UnsafeChecker::visit (MethodCallExpr &expr) +{ + TyTy::BaseType *method_type; + context.lookup_type (expr.get_method_name ().get_mappings ().get_hirid (), + &method_type); + + auto fn = *static_cast (method_type); + auto method = mappings.lookup_hir_implitem (fn.get_ref (), nullptr); + + if (!unsafe_context.is_in_context () && method) + check_unsafe_call (static_cast (method), expr.get_locus (), + "method"); + + expr.get_receiver ()->accept_vis (*this); + + for (auto &arg : expr.get_arguments ()) + arg->accept_vis (*this); +} + +void +UnsafeChecker::visit (FieldAccessExpr &expr) +{ + expr.get_receiver_expr ()->accept_vis (*this); + + if (unsafe_context.is_in_context ()) + return; + + TyTy::BaseType *receiver_ty; + auto ok = context.lookup_type ( + expr.get_receiver_expr ()->get_mappings ().get_hirid (), &receiver_ty); + rust_assert (ok); + + if (receiver_ty->get_kind () == TyTy::TypeKind::ADT) + { + auto maybe_union = static_cast (receiver_ty); + if (maybe_union->is_union ()) + rust_error_at ( + expr.get_locus (), + "access to union field requires unsafe function or block"); + } +} + +void +UnsafeChecker::visit (ClosureExprInner &expr) +{} + +void +UnsafeChecker::visit (BlockExpr &expr) +{ + for (auto &stmt : expr.get_statements ()) + stmt->accept_vis (*this); + + if (expr.has_expr ()) + expr.get_final_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (ClosureExprInnerTyped &expr) +{} + +void +UnsafeChecker::visit (ContinueExpr &expr) +{} + +void +UnsafeChecker::visit (BreakExpr &expr) +{ + if (expr.has_break_expr ()) + expr.get_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (RangeFromToExpr &expr) +{ + expr.get_from_expr ()->accept_vis (*this); + expr.get_to_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (RangeFromExpr &expr) +{ + expr.get_from_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (RangeToExpr &expr) +{ + expr.get_to_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (RangeFullExpr &expr) +{} + +void +UnsafeChecker::visit (RangeFromToInclExpr &expr) +{ + expr.get_from_expr ()->accept_vis (*this); + expr.get_to_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (RangeToInclExpr &expr) +{ + expr.get_to_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (ReturnExpr &expr) +{ + if (expr.has_return_expr ()) + expr.get_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (UnsafeBlockExpr &expr) +{ + unsafe_context.enter (expr.get_mappings ().get_hirid ()); + + expr.get_block_expr ()->accept_vis (*this); + + unsafe_context.exit (); +} + +void +UnsafeChecker::visit (LoopExpr &expr) +{ + expr.get_loop_block ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (WhileLoopExpr &expr) +{ + expr.get_predicate_expr ()->accept_vis (*this); + expr.get_loop_block ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (WhileLetLoopExpr &expr) +{ + expr.get_cond ()->accept_vis (*this); + expr.get_loop_block ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (ForLoopExpr &expr) +{ + expr.get_iterator_expr ()->accept_vis (*this); + expr.get_loop_block ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (IfExpr &expr) +{ + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (IfExprConseqElse &expr) +{ + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + expr.get_else_block ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (IfExprConseqIf &expr) +{ + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + expr.get_conseq_if_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (IfExprConseqIfLet &expr) +{ + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + + // TODO: Visit conseq if let expression +} + +void +UnsafeChecker::visit (IfLetExpr &expr) +{ + expr.get_scrutinee_expr ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (IfLetExprConseqElse &expr) +{ + expr.get_scrutinee_expr ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + + // TODO: Visit else expression +} + +void +UnsafeChecker::visit (IfLetExprConseqIf &expr) +{ + expr.get_scrutinee_expr ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (IfLetExprConseqIfLet &expr) +{ + expr.get_scrutinee_expr ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + + // TODO: Visit conseq if let expression +} + +void +UnsafeChecker::visit (MatchExpr &expr) +{ + expr.get_scrutinee_expr ()->accept_vis (*this); + + for (auto &match_arm : expr.get_match_cases ()) + match_arm.get_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (AwaitExpr &expr) +{ + // TODO: Visit expression +} + +void +UnsafeChecker::visit (AsyncBlockExpr &expr) +{ + // TODO: Visit block expression +} + +void +UnsafeChecker::visit (TypeParam ¶m) +{} + +void +UnsafeChecker::visit (ConstGenericParam ¶m) +{} + +void +UnsafeChecker::visit (LifetimeWhereClauseItem &item) +{} + +void +UnsafeChecker::visit (TypeBoundWhereClauseItem &item) +{} + +void +UnsafeChecker::visit (Module &module) +{ + for (auto &item : module.get_items ()) + item->accept_vis (*this); +} + +void +UnsafeChecker::visit (ExternCrate &crate) +{} + +void +UnsafeChecker::visit (UseTreeGlob &use_tree) +{} + +void +UnsafeChecker::visit (UseTreeList &use_tree) +{} + +void +UnsafeChecker::visit (UseTreeRebind &use_tree) +{} + +void +UnsafeChecker::visit (UseDeclaration &use_decl) +{} + +void +UnsafeChecker::visit (Function &function) +{ + auto is_unsafe_fn = function.get_qualifiers ().is_unsafe (); + + if (is_unsafe_fn) + unsafe_context.enter (function.get_mappings ().get_hirid ()); + + function.get_definition ()->accept_vis (*this); + + if (is_unsafe_fn) + unsafe_context.exit (); +} + +void +UnsafeChecker::visit (TypeAlias &type_alias) +{ + // FIXME: What do we need to do to handle type aliasing? Is it possible to + // have unsafe types? Type aliases on unsafe functions? +} + +void +UnsafeChecker::visit (StructStruct &struct_item) +{} + +void +UnsafeChecker::visit (TupleStruct &tuple_struct) +{} + +void +UnsafeChecker::visit (EnumItem &item) +{} + +void +UnsafeChecker::visit (EnumItemTuple &item) +{} + +void +UnsafeChecker::visit (EnumItemStruct &item) +{} + +void +UnsafeChecker::visit (EnumItemDiscriminant &item) +{} + +void +UnsafeChecker::visit (Enum &enum_item) +{} + +void +UnsafeChecker::visit (Union &union_item) +{} + +void +UnsafeChecker::visit (ConstantItem &const_item) +{ + const_item.get_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (StaticItem &static_item) +{ + static_item.get_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (TraitItemFunc &item) +{ + if (item.has_block_defined ()) + item.get_block_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (TraitItemConst &item) +{ + if (item.has_expr ()) + item.get_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (TraitItemType &item) +{} + +void +UnsafeChecker::visit (Trait &trait) +{ + // FIXME: Handle unsafe traits + for (auto &item : trait.get_trait_items ()) + item->accept_vis (*this); +} + +void +UnsafeChecker::visit (ImplBlock &impl) +{ + // FIXME: Handle unsafe impls + for (auto &item : impl.get_impl_items ()) + item->accept_vis (*this); +} + +void +UnsafeChecker::visit (ExternalStaticItem &item) +{} + +void +UnsafeChecker::visit (ExternalFunctionItem &item) +{} + +void +UnsafeChecker::visit (ExternBlock &block) +{ + // FIXME: Do we need to do this? + for (auto &item : block.get_extern_items ()) + item->accept_vis (*this); +} + +void +UnsafeChecker::visit (LiteralPattern &pattern) +{} + +void +UnsafeChecker::visit (IdentifierPattern &pattern) +{} + +void +UnsafeChecker::visit (WildcardPattern &pattern) +{} + +void +UnsafeChecker::visit (RangePatternBoundLiteral &bound) +{} + +void +UnsafeChecker::visit (RangePatternBoundPath &bound) +{} + +void +UnsafeChecker::visit (RangePatternBoundQualPath &bound) +{} + +void +UnsafeChecker::visit (RangePattern &pattern) +{} + +void +UnsafeChecker::visit (ReferencePattern &pattern) +{} + +void +UnsafeChecker::visit (StructPatternFieldTuplePat &field) +{} + +void +UnsafeChecker::visit (StructPatternFieldIdentPat &field) +{} + +void +UnsafeChecker::visit (StructPatternFieldIdent &field) +{} + +void +UnsafeChecker::visit (StructPattern &pattern) +{} + +void +UnsafeChecker::visit (TupleStructItemsNoRange &tuple_items) +{} + +void +UnsafeChecker::visit (TupleStructItemsRange &tuple_items) +{} + +void +UnsafeChecker::visit (TupleStructPattern &pattern) +{} + +void +UnsafeChecker::visit (TuplePatternItemsMultiple &tuple_items) +{} + +void +UnsafeChecker::visit (TuplePatternItemsRanged &tuple_items) +{} + +void +UnsafeChecker::visit (TuplePattern &pattern) +{} + +void +UnsafeChecker::visit (GroupedPattern &pattern) +{} + +void +UnsafeChecker::visit (SlicePattern &pattern) +{} + +void +UnsafeChecker::visit (EmptyStmt &stmt) +{} + +void +UnsafeChecker::visit (LetStmt &stmt) +{ + if (stmt.has_init_expr ()) + stmt.get_init_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (ExprStmtWithoutBlock &stmt) +{ + stmt.get_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (ExprStmtWithBlock &stmt) +{ + stmt.get_expr ()->accept_vis (*this); +} + +void +UnsafeChecker::visit (TraitBound &bound) +{} + +void +UnsafeChecker::visit (ImplTraitType &type) +{} + +void +UnsafeChecker::visit (TraitObjectType &type) +{} + +void +UnsafeChecker::visit (ParenthesisedType &type) +{} + +void +UnsafeChecker::visit (ImplTraitTypeOneBound &type) +{} + +void +UnsafeChecker::visit (TupleType &type) +{} + +void +UnsafeChecker::visit (NeverType &type) +{} + +void +UnsafeChecker::visit (RawPointerType &type) +{} + +void +UnsafeChecker::visit (ReferenceType &type) +{} + +void +UnsafeChecker::visit (ArrayType &type) +{} + +void +UnsafeChecker::visit (SliceType &type) +{} + +void +UnsafeChecker::visit (InferredType &type) +{} + +void +UnsafeChecker::visit (BareFunctionType &type) +{} + +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.h b/gcc/rust/checks/errors/rust-unsafe-checker.h new file mode 100644 index 00000000000..ae1eb509d78 --- /dev/null +++ b/gcc/rust/checks/errors/rust-unsafe-checker.h @@ -0,0 +1,191 @@ +// 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_UNSAFE_CHECKER_H +#define RUST_UNSAFE_CHECKER_H + +#include "rust-hir-visitor.h" +#include "rust-name-resolver.h" +#include "rust-hir-type-check.h" +#include "rust-stacked-contexts.h" + +namespace Rust { +namespace HIR { +class UnsafeChecker : public HIRFullVisitor +{ +public: + UnsafeChecker (); + + void go (HIR::Crate &crate); + +private: + /** + * Check if a mutable static or external static item is used outside of an + * unsafe context + */ + void check_use_of_static (HirId node_id, Location locus); + + /** + * Check if a call to an unsafe or external function is outside of an unsafe + * context + */ + void check_function_call (HirId node_id, Location locus); + + StackedContexts unsafe_context; + + Resolver::TypeCheckContext &context; + Resolver::Resolver &resolver; + Analysis::Mappings &mappings; + + virtual void visit (Lifetime &lifetime) override; + virtual void visit (LifetimeParam &lifetime_param) override; + virtual void visit (PathInExpression &path) override; + virtual void visit (TypePathSegment &segment) override; + virtual void visit (TypePathSegmentGeneric &segment) override; + virtual void visit (TypePathSegmentFunction &segment) override; + virtual void visit (TypePath &path) override; + virtual void visit (QualifiedPathInExpression &path) override; + virtual void visit (QualifiedPathInType &path) override; + virtual void visit (LiteralExpr &expr) override; + virtual void visit (BorrowExpr &expr) override; + virtual void visit (DereferenceExpr &expr) override; + virtual void visit (ErrorPropagationExpr &expr) override; + virtual void visit (NegationExpr &expr) override; + virtual void visit (ArithmeticOrLogicalExpr &expr) override; + virtual void visit (ComparisonExpr &expr) override; + virtual void visit (LazyBooleanExpr &expr) override; + virtual void visit (TypeCastExpr &expr) override; + virtual void visit (AssignmentExpr &expr) override; + virtual void visit (CompoundAssignmentExpr &expr) override; + virtual void visit (GroupedExpr &expr) override; + virtual void visit (ArrayElemsValues &elems) override; + virtual void visit (ArrayElemsCopied &elems) override; + virtual void visit (ArrayExpr &expr) override; + virtual void visit (ArrayIndexExpr &expr) override; + virtual void visit (TupleExpr &expr) override; + virtual void visit (TupleIndexExpr &expr) override; + virtual void visit (StructExprStruct &expr) override; + virtual void visit (StructExprFieldIdentifier &field) override; + virtual void visit (StructExprFieldIdentifierValue &field) override; + virtual void visit (StructExprFieldIndexValue &field) override; + virtual void visit (StructExprStructFields &expr) override; + virtual void visit (StructExprStructBase &expr) override; + virtual void visit (CallExpr &expr) override; + virtual void visit (MethodCallExpr &expr) override; + virtual void visit (FieldAccessExpr &expr) override; + virtual void visit (ClosureExprInner &expr) override; + virtual void visit (BlockExpr &expr) override; + virtual void visit (ClosureExprInnerTyped &expr) override; + virtual void visit (ContinueExpr &expr) override; + virtual void visit (BreakExpr &expr) override; + virtual void visit (RangeFromToExpr &expr) override; + virtual void visit (RangeFromExpr &expr) override; + virtual void visit (RangeToExpr &expr) override; + virtual void visit (RangeFullExpr &expr) override; + virtual void visit (RangeFromToInclExpr &expr) override; + virtual void visit (RangeToInclExpr &expr) override; + virtual void visit (ReturnExpr &expr) override; + virtual void visit (UnsafeBlockExpr &expr) override; + virtual void visit (LoopExpr &expr) override; + virtual void visit (WhileLoopExpr &expr) override; + virtual void visit (WhileLetLoopExpr &expr) override; + virtual void visit (ForLoopExpr &expr) override; + virtual void visit (IfExpr &expr) override; + virtual void visit (IfExprConseqElse &expr) override; + virtual void visit (IfExprConseqIf &expr) override; + virtual void visit (IfExprConseqIfLet &expr) override; + virtual void visit (IfLetExpr &expr) override; + virtual void visit (IfLetExprConseqElse &expr) override; + virtual void visit (IfLetExprConseqIf &expr) override; + virtual void visit (IfLetExprConseqIfLet &expr) override; + virtual void visit (MatchExpr &expr) override; + virtual void visit (AwaitExpr &expr) override; + virtual void visit (AsyncBlockExpr &expr) override; + virtual void visit (TypeParam ¶m) override; + virtual void visit (ConstGenericParam ¶m) override; + virtual void visit (LifetimeWhereClauseItem &item) override; + virtual void visit (TypeBoundWhereClauseItem &item) override; + virtual void visit (Module &module) override; + virtual void visit (ExternCrate &crate) override; + virtual void visit (UseTreeGlob &use_tree) override; + virtual void visit (UseTreeList &use_tree) override; + virtual void visit (UseTreeRebind &use_tree) override; + virtual void visit (UseDeclaration &use_decl) override; + virtual void visit (Function &function) override; + virtual void visit (TypeAlias &type_alias) override; + virtual void visit (StructStruct &struct_item) override; + virtual void visit (TupleStruct &tuple_struct) override; + virtual void visit (EnumItem &item) override; + virtual void visit (EnumItemTuple &item) override; + virtual void visit (EnumItemStruct &item) override; + virtual void visit (EnumItemDiscriminant &item) override; + virtual void visit (Enum &enum_item) override; + virtual void visit (Union &union_item) override; + virtual void visit (ConstantItem &const_item) override; + virtual void visit (StaticItem &static_item) override; + virtual void visit (TraitItemFunc &item) override; + virtual void visit (TraitItemConst &item) override; + virtual void visit (TraitItemType &item) override; + virtual void visit (Trait &trait) override; + virtual void visit (ImplBlock &impl) override; + virtual void visit (ExternalStaticItem &item) override; + virtual void visit (ExternalFunctionItem &item) override; + virtual void visit (ExternBlock &block) override; + virtual void visit (LiteralPattern &pattern) override; + virtual void visit (IdentifierPattern &pattern) override; + virtual void visit (WildcardPattern &pattern) override; + virtual void visit (RangePatternBoundLiteral &bound) override; + virtual void visit (RangePatternBoundPath &bound) override; + virtual void visit (RangePatternBoundQualPath &bound) override; + virtual void visit (RangePattern &pattern) override; + virtual void visit (ReferencePattern &pattern) override; + virtual void visit (StructPatternFieldTuplePat &field) override; + virtual void visit (StructPatternFieldIdentPat &field) override; + virtual void visit (StructPatternFieldIdent &field) override; + virtual void visit (StructPattern &pattern) override; + virtual void visit (TupleStructItemsNoRange &tuple_items) override; + virtual void visit (TupleStructItemsRange &tuple_items) override; + virtual void visit (TupleStructPattern &pattern) override; + virtual void visit (TuplePatternItemsMultiple &tuple_items) override; + virtual void visit (TuplePatternItemsRanged &tuple_items) override; + virtual void visit (TuplePattern &pattern) override; + virtual void visit (GroupedPattern &pattern) override; + virtual void visit (SlicePattern &pattern) override; + virtual void visit (EmptyStmt &stmt) override; + virtual void visit (LetStmt &stmt) override; + virtual void visit (ExprStmtWithoutBlock &stmt) override; + virtual void visit (ExprStmtWithBlock &stmt) override; + virtual void visit (TraitBound &bound) override; + virtual void visit (ImplTraitType &type) override; + virtual void visit (TraitObjectType &type) override; + virtual void visit (ParenthesisedType &type) override; + virtual void visit (ImplTraitTypeOneBound &type) override; + virtual void visit (TupleType &type) override; + virtual void visit (NeverType &type) override; + virtual void visit (RawPointerType &type) override; + virtual void visit (ReferenceType &type) override; + virtual void visit (ArrayType &type) override; + virtual void visit (SliceType &type) override; + virtual void visit (InferredType &type) override; + virtual void visit (BareFunctionType &type) override; +}; + +} // namespace HIR +} // namespace Rust + +#endif /* !RUST_UNSAFE_CHECKER_H */ From patchwork Wed Aug 24 11:59:43 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 57001 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 4F79A3989FF8 for ; Wed, 24 Aug 2022 12:07:20 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by sourceware.org (Postfix) with ESMTPS id B50F5380DFA2; Wed, 24 Aug 2022 12:01:06 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org B50F5380DFA2 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wm1-x32d.google.com with SMTP id k17so8662568wmr.2; Wed, 24 Aug 2022 05:01:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=yRBPc9YdpJc/UbKOxruyWWT3R50qmn9olUn7RiM9JYw=; b=Fyi04gwq2A/fIQPlRNli4KSiDaOknOnPk1NcyWWWk0lVd4JFVyDue66nBcny0/ufuR SrG8sfo0nwRdH88Z0goJR/LiE5tBWmKQWI4LK7HnFV9S7PuiyABDgG/dskH5PEjOuLSC AVr0M0oR6G1QiJfJ0TuldaeH/oTbC3LexmVVbfv66NuiKsoXOYLmHVASbQDvAIAJa+QS H3gZyQFm/LkOlpYYT602uQsqpECIpXDMxSAuJfi8W2JM8mM+hjN3FjipkQ+8JEKi11p+ SwV3R/CQCSEwwhjNGr7nqSafdy6Rp9oAnESMMe79C/zjX/STCyxyu2SrHkSeoIsKan8g q++g== 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; bh=yRBPc9YdpJc/UbKOxruyWWT3R50qmn9olUn7RiM9JYw=; b=dCQZN2D8hitUpKM7/MjGrE65fM0yMPb73rcPIUk6yDwOKWTYDxzwRXWxJptbe2E3ey wWY0ENGEnkCZiaf+itKbanz6yCNiGCK64KtlC2c2ICpZ8fJWiVUM1K/6Zmvx6qQLrFbC VDh1BY6ENhHEXiGIL1IGx3JssoNh/Cae+DJbfxz+OaTFF+xbup911Qu1ihIPrGytPxM+ m7w8C8Hq3Y1w9QhPIw76NJWw33LC/jQ5KYQx63tYvR4k6ElRF7JSLqWo3LJhkNPbhzVs S9wCRGS3YkTBdW1vyrjR+PJEpcOF3zlSw/DM8IuZHr5KfGGJCoVEuCfVf7AtSgSzKsf/ M1KA== X-Gm-Message-State: ACgBeo3NuCNkqk1jRxGHT2+Mn2lnCvRfdC73zwp9dzRHcEmi77ohfuAo sSdn3cEqwGL9pcKygJIrvuK7LM23Nw8= X-Google-Smtp-Source: AA6agR5lbpPnJmmgWWHcjdPle4wb9/qE8iWenaQPJB4kvxlonDERme2lQSI1qZKxLCjx3/7eyUZEvg== X-Received: by 2002:a05:600c:4e92:b0:3a5:fd90:24e3 with SMTP id f18-20020a05600c4e9200b003a5fd9024e3mr5200587wmq.59.1661342465029; Wed, 24 Aug 2022 05:01:05 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.01.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:01:03 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 24/37] gccrs: Add const checker Date: Wed, 24 Aug 2022 12:59:43 +0100 Message-Id: <20220824115956.737931-25-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: Arthur Cohen , gcc-rust@gcc.gnu.org Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Arthur Cohen Similarly to the unsafe checker, constant evaluation can only be performed in a few contexts and include restrictions on the Rust language. Should the user fail to uphold those conditions, errors will be reported and the compilation pipeline interrupted. These contexts are as follow: - Array type length expressions - Array repeat length expressions - Constants - Statics - Enum discriminants - Const generic arguments In these contexts, the user is restricted to calling only functions marked as `const` or perform arithmetic operations only on certain types, among other restrictions. --- gcc/rust/checks/errors/rust-const-checker.cc | 844 +++++++++++++++++++ gcc/rust/checks/errors/rust-const-checker.h | 189 +++++ 2 files changed, 1033 insertions(+) create mode 100644 gcc/rust/checks/errors/rust-const-checker.cc create mode 100644 gcc/rust/checks/errors/rust-const-checker.h diff --git a/gcc/rust/checks/errors/rust-const-checker.cc b/gcc/rust/checks/errors/rust-const-checker.cc new file mode 100644 index 00000000000..35c61fe03f0 --- /dev/null +++ b/gcc/rust/checks/errors/rust-const-checker.cc @@ -0,0 +1,844 @@ +// 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 +// . + +#include "rust-const-checker.h" +#include "rust-hir.h" +#include "rust-hir-expr.h" +#include "rust-hir-stmt.h" +#include "rust-hir-item.h" + +namespace Rust { +namespace HIR { + +ConstChecker::ConstChecker () + : resolver (*Resolver::Resolver::get ()), + mappings (*Analysis::Mappings::get ()) +{} + +void +ConstChecker::go (HIR::Crate &crate) +{ + for (auto &item : crate.items) + item->accept_vis (*this); +} + +bool +ConstChecker::is_const_extern_fn (HIR::ExternalFunctionItem &fn) +{ + // FIXME: Is it really how we want to handle `rustc_const_stable` + // and `rustc_const_unstable`? + // TODO: Add these attributes to the attribute check and handle + // `stable` and `unstable` as well + return std::any_of ( + fn.get_outer_attrs ().begin (), fn.get_outer_attrs ().end (), + [] (const AST::Attribute &attr) { + // `starts_with` in C++11... + return attr.get_path ().as_string ().rfind ("rustc_const_", 0) == 0; + }); +} + +void +ConstChecker::visit (Lifetime &lifetime) +{} + +void +ConstChecker::visit (LifetimeParam &lifetime_param) +{} + +void +ConstChecker::visit (PathInExpression &path) +{} + +void +ConstChecker::visit (TypePathSegment &segment) +{} + +void +ConstChecker::visit (TypePathSegmentGeneric &segment) +{} + +void +ConstChecker::visit (TypePathSegmentFunction &segment) +{} + +void +ConstChecker::visit (TypePath &path) +{} + +void +ConstChecker::visit (QualifiedPathInExpression &path) +{} + +void +ConstChecker::visit (QualifiedPathInType &path) +{} + +void +ConstChecker::visit (LiteralExpr &expr) +{} + +void +ConstChecker::visit (BorrowExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (DereferenceExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (ErrorPropagationExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (NegationExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (ArithmeticOrLogicalExpr &expr) +{ + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); +} + +void +ConstChecker::visit (ComparisonExpr &expr) +{ + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); +} + +void +ConstChecker::visit (LazyBooleanExpr &expr) +{ + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); +} + +void +ConstChecker::visit (TypeCastExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (AssignmentExpr &expr) +{ + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); +} + +void +ConstChecker::visit (CompoundAssignmentExpr &expr) +{ + expr.get_left_expr ()->accept_vis (*this); + expr.get_right_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (GroupedExpr &expr) +{ + expr.get_expr_in_parens ()->accept_vis (*this); +} + +void +ConstChecker::visit (ArrayElemsValues &elems) +{ + for (auto &elem : elems.get_values ()) + elem->accept_vis (*this); +} + +void +ConstChecker::visit (ArrayElemsCopied &elems) +{ + elems.get_elem_to_copy ()->accept_vis (*this); + + const_context.enter (elems.get_mappings ().get_hirid ()); + + elems.get_num_copies_expr ()->accept_vis (*this); + + const_context.exit (); +} + +void +ConstChecker::visit (ArrayExpr &expr) +{ + expr.get_internal_elements ()->accept_vis (*this); +} + +void +ConstChecker::visit (ArrayIndexExpr &expr) +{ + expr.get_array_expr ()->accept_vis (*this); + expr.get_index_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (TupleExpr &expr) +{ + for (auto &elem : expr.get_tuple_elems ()) + elem->accept_vis (*this); +} + +void +ConstChecker::visit (TupleIndexExpr &expr) +{ + expr.get_tuple_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (StructExprStruct &expr) +{} + +void +ConstChecker::visit (StructExprFieldIdentifier &field) +{} + +void +ConstChecker::visit (StructExprFieldIdentifierValue &field) +{ + field.get_value ()->accept_vis (*this); +} + +void +ConstChecker::visit (StructExprFieldIndexValue &field) +{ + field.get_value ()->accept_vis (*this); +} + +void +ConstChecker::visit (StructExprStructFields &expr) +{ + for (auto &field : expr.get_fields ()) + field->accept_vis (*this); +} + +void +ConstChecker::visit (StructExprStructBase &expr) +{} + +void +ConstChecker::check_function_call (HirId fn_id, Location locus) +{ + if (!const_context.is_in_context ()) + return; + + auto maybe_fn = mappings.lookup_hir_item (fn_id); + if (maybe_fn && maybe_fn->get_item_kind () != Item::ItemKind::Function) + return; + + // There are const extern functions (intrinsics) + // TODO: Should we check the ABI is only "rust intrinsics"? Is that handled + // elsewhere? + HirId parent_block; + auto maybe_extern_item + = mappings.lookup_hir_extern_item (fn_id, &parent_block); + if (maybe_extern_item + && maybe_extern_item->get_extern_kind () + != ExternalItem::ExternKind::Function) + return; + + auto is_error = false; + if (maybe_fn) + { + auto fn = static_cast (maybe_fn); + if (!fn->get_qualifiers ().is_const ()) + is_error = true; + } + + if (maybe_extern_item) + { + { + auto fn = static_cast (maybe_extern_item); + if (!is_const_extern_fn (*fn)) + is_error = true; + } + } + + if (is_error) + rust_error_at (locus, "only functions marked as % are allowed to " + "be called from constant contexts"); +} + +void +ConstChecker::visit (CallExpr &expr) +{ + auto fn = expr.get_fnexpr (); + if (!fn) + return; + + NodeId ast_node_id = fn->get_mappings ().get_nodeid (); + NodeId ref_node_id; + HirId definition_id; + + // We don't care about types here + if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) + return; + + rust_assert (mappings.lookup_node_to_hir (ref_node_id, &definition_id)); + + check_function_call (definition_id, expr.get_locus ()); + + for (auto &arg : expr.get_arguments ()) + arg->accept_vis (*this); +} + +void +ConstChecker::visit (MethodCallExpr &expr) +{ + expr.get_receiver ()->accept_vis (*this); + + for (auto &arg : expr.get_arguments ()) + arg->accept_vis (*this); +} + +void +ConstChecker::visit (FieldAccessExpr &expr) +{ + expr.get_receiver_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (ClosureExprInner &expr) +{} + +void +ConstChecker::visit (BlockExpr &expr) +{ + for (auto &stmt : expr.get_statements ()) + stmt->accept_vis (*this); + + if (expr.has_expr ()) + expr.get_final_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (ClosureExprInnerTyped &expr) +{} + +void +ConstChecker::visit (ContinueExpr &expr) +{} + +void +ConstChecker::visit (BreakExpr &expr) +{ + if (expr.has_break_expr ()) + expr.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (RangeFromToExpr &expr) +{ + expr.get_from_expr ()->accept_vis (*this); + expr.get_to_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (RangeFromExpr &expr) +{ + expr.get_from_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (RangeToExpr &expr) +{ + expr.get_to_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (RangeFullExpr &expr) +{} + +void +ConstChecker::visit (RangeFromToInclExpr &expr) +{ + expr.get_from_expr ()->accept_vis (*this); + expr.get_to_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (RangeToInclExpr &expr) +{ + // FIXME: Visit to_expr +} + +void +ConstChecker::visit (ReturnExpr &expr) +{ + if (expr.has_return_expr ()) + expr.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (UnsafeBlockExpr &expr) +{ + expr.get_block_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (LoopExpr &expr) +{ + expr.get_loop_block ()->accept_vis (*this); +} + +void +ConstChecker::visit (WhileLoopExpr &expr) +{ + expr.get_predicate_expr ()->accept_vis (*this); + expr.get_loop_block ()->accept_vis (*this); +} + +void +ConstChecker::visit (WhileLetLoopExpr &expr) +{ + expr.get_cond ()->accept_vis (*this); + expr.get_loop_block ()->accept_vis (*this); +} + +void +ConstChecker::visit (ForLoopExpr &expr) +{ + expr.get_iterator_expr ()->accept_vis (*this); + expr.get_loop_block ()->accept_vis (*this); +} + +void +ConstChecker::visit (IfExpr &expr) +{ + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); +} + +void +ConstChecker::visit (IfExprConseqElse &expr) +{ + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + expr.get_else_block ()->accept_vis (*this); +} + +void +ConstChecker::visit (IfExprConseqIf &expr) +{ + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + expr.get_conseq_if_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (IfExprConseqIfLet &expr) +{ + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + + // TODO: Visit conseq if let expression +} + +void +ConstChecker::visit (IfLetExpr &expr) +{ + expr.get_scrutinee_expr ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); +} + +void +ConstChecker::visit (IfLetExprConseqElse &expr) +{ + expr.get_scrutinee_expr ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + + // TODO: Visit else expression +} + +void +ConstChecker::visit (IfLetExprConseqIf &expr) +{ + expr.get_scrutinee_expr ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); +} + +void +ConstChecker::visit (IfLetExprConseqIfLet &expr) +{ + expr.get_scrutinee_expr ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + + // TODO: Visit conseq if let expression +} + +void +ConstChecker::visit (MatchExpr &expr) +{ + expr.get_scrutinee_expr ()->accept_vis (*this); + + for (auto &match_arm : expr.get_match_cases ()) + match_arm.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (AwaitExpr &expr) +{ + // TODO: Visit expression +} + +void +ConstChecker::visit (AsyncBlockExpr &expr) +{ + // TODO: Visit block expression +} + +void +ConstChecker::visit (TypeParam ¶m) +{} + +void +ConstChecker::visit (ConstGenericParam ¶m) +{} + +void +ConstChecker::visit (LifetimeWhereClauseItem &item) +{} + +void +ConstChecker::visit (TypeBoundWhereClauseItem &item) +{} + +void +ConstChecker::visit (Module &module) +{ + for (auto &item : module.get_items ()) + item->accept_vis (*this); +} + +void +ConstChecker::visit (ExternCrate &crate) +{} + +void +ConstChecker::visit (UseTreeGlob &use_tree) +{} + +void +ConstChecker::visit (UseTreeList &use_tree) +{} + +void +ConstChecker::visit (UseTreeRebind &use_tree) +{} + +void +ConstChecker::visit (UseDeclaration &use_decl) +{} + +void +ConstChecker::visit (Function &function) +{ + auto const_fn = function.get_qualifiers ().is_const (); + if (const_fn) + const_context.enter (function.get_mappings ().get_hirid ()); + + for (auto ¶m : function.get_function_params ()) + param.get_type ()->accept_vis (*this); + + function.get_definition ()->accept_vis (*this); + + if (const_fn) + const_context.exit (); +} + +void +ConstChecker::visit (TypeAlias &type_alias) +{} + +void +ConstChecker::visit (StructStruct &struct_item) +{} + +void +ConstChecker::visit (TupleStruct &tuple_struct) +{} + +void +ConstChecker::visit (EnumItem &item) +{} + +void +ConstChecker::visit (EnumItemTuple &item) +{} + +void +ConstChecker::visit (EnumItemStruct &item) +{} + +void +ConstChecker::visit (EnumItemDiscriminant &item) +{ + const_context.enter (item.get_mappings ().get_hirid ()); + + item.get_discriminant_expression ()->accept_vis (*this); + + const_context.exit (); +} + +void +ConstChecker::visit (Enum &enum_item) +{} + +void +ConstChecker::visit (Union &union_item) +{} + +void +ConstChecker::visit (ConstantItem &const_item) +{ + const_context.enter (const_item.get_mappings ().get_hirid ()); + + const_item.get_expr ()->accept_vis (*this); + + const_context.exit (); +} + +void +ConstChecker::visit (StaticItem &static_item) +{ + const_context.enter (static_item.get_mappings ().get_hirid ()); + + static_item.get_expr ()->accept_vis (*this); + + const_context.exit (); +} + +void +ConstChecker::visit (TraitItemFunc &item) +{ + if (item.has_block_defined ()) + item.get_block_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (TraitItemConst &item) +{ + if (item.has_expr ()) + item.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (TraitItemType &item) +{} + +void +ConstChecker::visit (Trait &trait) +{ + for (auto &item : trait.get_trait_items ()) + item->accept_vis (*this); +} + +void +ConstChecker::visit (ImplBlock &impl) +{ + for (auto &item : impl.get_impl_items ()) + item->accept_vis (*this); +} + +void +ConstChecker::visit (ExternalStaticItem &item) +{} + +void +ConstChecker::visit (ExternalFunctionItem &item) +{} + +void +ConstChecker::visit (ExternBlock &block) +{ + // FIXME: Do we need to do this? + for (auto &item : block.get_extern_items ()) + item->accept_vis (*this); +} + +void +ConstChecker::visit (LiteralPattern &pattern) +{} + +void +ConstChecker::visit (IdentifierPattern &pattern) +{} + +void +ConstChecker::visit (WildcardPattern &pattern) +{} + +void +ConstChecker::visit (RangePatternBoundLiteral &bound) +{} + +void +ConstChecker::visit (RangePatternBoundPath &bound) +{} + +void +ConstChecker::visit (RangePatternBoundQualPath &bound) +{} + +void +ConstChecker::visit (RangePattern &pattern) +{} + +void +ConstChecker::visit (ReferencePattern &pattern) +{} + +void +ConstChecker::visit (StructPatternFieldTuplePat &field) +{} + +void +ConstChecker::visit (StructPatternFieldIdentPat &field) +{} + +void +ConstChecker::visit (StructPatternFieldIdent &field) +{} + +void +ConstChecker::visit (StructPattern &pattern) +{} + +void +ConstChecker::visit (TupleStructItemsNoRange &tuple_items) +{} + +void +ConstChecker::visit (TupleStructItemsRange &tuple_items) +{} + +void +ConstChecker::visit (TupleStructPattern &pattern) +{} + +void +ConstChecker::visit (TuplePatternItemsMultiple &tuple_items) +{} + +void +ConstChecker::visit (TuplePatternItemsRanged &tuple_items) +{} + +void +ConstChecker::visit (TuplePattern &pattern) +{} + +void +ConstChecker::visit (GroupedPattern &pattern) +{} + +void +ConstChecker::visit (SlicePattern &pattern) +{} + +void +ConstChecker::visit (EmptyStmt &stmt) +{} + +void +ConstChecker::visit (LetStmt &stmt) +{ + if (stmt.has_init_expr ()) + stmt.get_init_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (ExprStmtWithoutBlock &stmt) +{ + stmt.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (ExprStmtWithBlock &stmt) +{ + stmt.get_expr ()->accept_vis (*this); +} + +void +ConstChecker::visit (TraitBound &bound) +{} + +void +ConstChecker::visit (ImplTraitType &type) +{} + +void +ConstChecker::visit (TraitObjectType &type) +{} + +void +ConstChecker::visit (ParenthesisedType &type) +{} + +void +ConstChecker::visit (ImplTraitTypeOneBound &type) +{} + +void +ConstChecker::visit (TupleType &type) +{} + +void +ConstChecker::visit (NeverType &type) +{} + +void +ConstChecker::visit (RawPointerType &type) +{} + +void +ConstChecker::visit (ReferenceType &type) +{} + +void +ConstChecker::visit (ArrayType &type) +{ + const_context.enter (type.get_mappings ().get_hirid ()); + + type.get_size_expr ()->accept_vis (*this); + + const_context.exit (); +} + +void +ConstChecker::visit (SliceType &type) +{} + +void +ConstChecker::visit (InferredType &type) +{} + +void +ConstChecker::visit (BareFunctionType &type) +{} + +} // namespace HIR +} // namespace Rust diff --git a/gcc/rust/checks/errors/rust-const-checker.h b/gcc/rust/checks/errors/rust-const-checker.h new file mode 100644 index 00000000000..50838d18996 --- /dev/null +++ b/gcc/rust/checks/errors/rust-const-checker.h @@ -0,0 +1,189 @@ +// 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_CONST_CHECKER_H +#define RUST_CONST_CHECKER_H + +#include "rust-hir-visitor.h" +#include "rust-hir-type-check.h" +#include "rust-stacked-contexts.h" +#include "rust-name-resolver.h" + +namespace Rust { +namespace HIR { +class ConstChecker : public HIRFullVisitor +{ +public: + ConstChecker (); + + void go (HIR::Crate &crate); + + /** + * Check if an item is a const extern item or not + * TODO: Move this to a const compilation context class or an attribute + * checking class + */ + static bool is_const_extern_fn (HIR::ExternalFunctionItem &fn); + +private: + /** + * Check that only const functions are called in const contexts + */ + void check_function_call (HirId fn_id, Location locus); + + StackedContexts const_context; + Resolver::Resolver &resolver; + Analysis::Mappings &mappings; + + virtual void visit (Lifetime &lifetime) override; + virtual void visit (LifetimeParam &lifetime_param) override; + virtual void visit (PathInExpression &path) override; + virtual void visit (TypePathSegment &segment) override; + virtual void visit (TypePathSegmentGeneric &segment) override; + virtual void visit (TypePathSegmentFunction &segment) override; + virtual void visit (TypePath &path) override; + virtual void visit (QualifiedPathInExpression &path) override; + virtual void visit (QualifiedPathInType &path) override; + virtual void visit (LiteralExpr &expr) override; + virtual void visit (BorrowExpr &expr) override; + virtual void visit (DereferenceExpr &expr) override; + virtual void visit (ErrorPropagationExpr &expr) override; + virtual void visit (NegationExpr &expr) override; + virtual void visit (ArithmeticOrLogicalExpr &expr) override; + virtual void visit (ComparisonExpr &expr) override; + virtual void visit (LazyBooleanExpr &expr) override; + virtual void visit (TypeCastExpr &expr) override; + virtual void visit (AssignmentExpr &expr) override; + virtual void visit (CompoundAssignmentExpr &expr) override; + virtual void visit (GroupedExpr &expr) override; + virtual void visit (ArrayElemsValues &elems) override; + virtual void visit (ArrayElemsCopied &elems) override; + virtual void visit (ArrayExpr &expr) override; + virtual void visit (ArrayIndexExpr &expr) override; + virtual void visit (TupleExpr &expr) override; + virtual void visit (TupleIndexExpr &expr) override; + virtual void visit (StructExprStruct &expr) override; + virtual void visit (StructExprFieldIdentifier &field) override; + virtual void visit (StructExprFieldIdentifierValue &field) override; + virtual void visit (StructExprFieldIndexValue &field) override; + virtual void visit (StructExprStructFields &expr) override; + virtual void visit (StructExprStructBase &expr) override; + virtual void visit (CallExpr &expr) override; + virtual void visit (MethodCallExpr &expr) override; + virtual void visit (FieldAccessExpr &expr) override; + virtual void visit (ClosureExprInner &expr) override; + virtual void visit (BlockExpr &expr) override; + virtual void visit (ClosureExprInnerTyped &expr) override; + virtual void visit (ContinueExpr &expr) override; + virtual void visit (BreakExpr &expr) override; + virtual void visit (RangeFromToExpr &expr) override; + virtual void visit (RangeFromExpr &expr) override; + virtual void visit (RangeToExpr &expr) override; + virtual void visit (RangeFullExpr &expr) override; + virtual void visit (RangeFromToInclExpr &expr) override; + virtual void visit (RangeToInclExpr &expr) override; + virtual void visit (ReturnExpr &expr) override; + virtual void visit (UnsafeBlockExpr &expr) override; + virtual void visit (LoopExpr &expr) override; + virtual void visit (WhileLoopExpr &expr) override; + virtual void visit (WhileLetLoopExpr &expr) override; + virtual void visit (ForLoopExpr &expr) override; + virtual void visit (IfExpr &expr) override; + virtual void visit (IfExprConseqElse &expr) override; + virtual void visit (IfExprConseqIf &expr) override; + virtual void visit (IfExprConseqIfLet &expr) override; + virtual void visit (IfLetExpr &expr) override; + virtual void visit (IfLetExprConseqElse &expr) override; + virtual void visit (IfLetExprConseqIf &expr) override; + virtual void visit (IfLetExprConseqIfLet &expr) override; + virtual void visit (MatchExpr &expr) override; + virtual void visit (AwaitExpr &expr) override; + virtual void visit (AsyncBlockExpr &expr) override; + virtual void visit (TypeParam ¶m) override; + virtual void visit (ConstGenericParam ¶m) override; + virtual void visit (LifetimeWhereClauseItem &item) override; + virtual void visit (TypeBoundWhereClauseItem &item) override; + virtual void visit (Module &module) override; + virtual void visit (ExternCrate &crate) override; + virtual void visit (UseTreeGlob &use_tree) override; + virtual void visit (UseTreeList &use_tree) override; + virtual void visit (UseTreeRebind &use_tree) override; + virtual void visit (UseDeclaration &use_decl) override; + virtual void visit (Function &function) override; + virtual void visit (TypeAlias &type_alias) override; + virtual void visit (StructStruct &struct_item) override; + virtual void visit (TupleStruct &tuple_struct) override; + virtual void visit (EnumItem &item) override; + virtual void visit (EnumItemTuple &item) override; + virtual void visit (EnumItemStruct &item) override; + virtual void visit (EnumItemDiscriminant &item) override; + virtual void visit (Enum &enum_item) override; + virtual void visit (Union &union_item) override; + virtual void visit (ConstantItem &const_item) override; + virtual void visit (StaticItem &static_item) override; + virtual void visit (TraitItemFunc &item) override; + virtual void visit (TraitItemConst &item) override; + virtual void visit (TraitItemType &item) override; + virtual void visit (Trait &trait) override; + virtual void visit (ImplBlock &impl) override; + virtual void visit (ExternalStaticItem &item) override; + virtual void visit (ExternalFunctionItem &item) override; + virtual void visit (ExternBlock &block) override; + virtual void visit (LiteralPattern &pattern) override; + virtual void visit (IdentifierPattern &pattern) override; + virtual void visit (WildcardPattern &pattern) override; + virtual void visit (RangePatternBoundLiteral &bound) override; + virtual void visit (RangePatternBoundPath &bound) override; + virtual void visit (RangePatternBoundQualPath &bound) override; + virtual void visit (RangePattern &pattern) override; + virtual void visit (ReferencePattern &pattern) override; + virtual void visit (StructPatternFieldTuplePat &field) override; + virtual void visit (StructPatternFieldIdentPat &field) override; + virtual void visit (StructPatternFieldIdent &field) override; + virtual void visit (StructPattern &pattern) override; + virtual void visit (TupleStructItemsNoRange &tuple_items) override; + virtual void visit (TupleStructItemsRange &tuple_items) override; + virtual void visit (TupleStructPattern &pattern) override; + virtual void visit (TuplePatternItemsMultiple &tuple_items) override; + virtual void visit (TuplePatternItemsRanged &tuple_items) override; + virtual void visit (TuplePattern &pattern) override; + virtual void visit (GroupedPattern &pattern) override; + virtual void visit (SlicePattern &pattern) override; + virtual void visit (EmptyStmt &stmt) override; + virtual void visit (LetStmt &stmt) override; + virtual void visit (ExprStmtWithoutBlock &stmt) override; + virtual void visit (ExprStmtWithBlock &stmt) override; + virtual void visit (TraitBound &bound) override; + virtual void visit (ImplTraitType &type) override; + virtual void visit (TraitObjectType &type) override; + virtual void visit (ParenthesisedType &type) override; + virtual void visit (ImplTraitTypeOneBound &type) override; + virtual void visit (TupleType &type) override; + virtual void visit (NeverType &type) override; + virtual void visit (RawPointerType &type) override; + virtual void visit (ReferenceType &type) override; + virtual void visit (ArrayType &type) override; + virtual void visit (SliceType &type) override; + virtual void visit (InferredType &type) override; + virtual void visit (BareFunctionType &type) override; +}; + +} // namespace HIR +} // namespace Rust + +#endif /* !RUST_CONST_CHECKER_H */ From patchwork Wed Aug 24 11:59:44 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56989 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 BC453396D817 for ; Wed, 24 Aug 2022 12:04:11 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x32b.google.com (mail-wm1-x32b.google.com [IPv6:2a00:1450:4864:20::32b]) by sourceware.org (Postfix) with ESMTPS id 23DDD385022F; Wed, 24 Aug 2022 12:01:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 23DDD385022F Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wm1-x32b.google.com with SMTP id k18-20020a05600c0b5200b003a5dab49d0bso711115wmr.3; Wed, 24 Aug 2022 05:01:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=g+XAU5zJCKM/WtsbNuZ9oIAGDyQ4juA7YKh51gc2H7o=; b=iA9E9Uawk0l7YRpjaBMUw5ANIy0E2n6QNdOChlxjXlD1FJE7WXA+P5DXeyYXj+SNNA QsG+16JRVwa0vvsLo39jGFwvcViX115QMPj1oa75DgrS/LEjWWY08VD7iu7CyG7aMsK5 PU5aLkm64Ygv6l9x7C86w9JeISUcrB2efzsmTYLoYw/ceZiwRlQeXJbbLwOy2E1CzaLl aO6oSe5jn2pI6fAQhAjAbk78WqcCO9CnNW08zrgqQo6anUCy/uzwFyApnlMLa8uNFrmD ysKNAXZ2PeKlXW4p6yFLBUFQ6DcaheIlNrSQ/IZ01Yqu3p67f+5Vv4Hc55Mr13l3JxMg yRQg== 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; bh=g+XAU5zJCKM/WtsbNuZ9oIAGDyQ4juA7YKh51gc2H7o=; b=FQgHtmigEVqcK+f3W4Jbo8AIjxfuMGUS1jvpCWCULGQLYPP+Ne3dFm6CGiXly2B82m 3TooRquIWHVTg++cddD7BM21LS6+qaiq0DTe8hCmkc6uYPKdE48wtP075FnKvwqWsQyQ IAutzHsRb8vAfl5ayocozWUw9ZOCKdyB2ifmooqm2gNx6PljD3MBWGI4XibeEaSUm8fF jZMeDVVBIS3JHzbemxS2coD0u+bxh8gtputLHcalWp6Sk/0tCvIpRYYjjMoNa9xx3OUq 5Xy5frtoGg1ipv8GV2MMAo1KtxI9fUpzZ/o6pNj8b2fusf3lakKgdKDyGPo0i0JMMli8 ABOQ== X-Gm-Message-State: ACgBeo1rxZDSA8zu2g5NWKuBHUKGNOr7LwwHsWi6pUiNwttEQsQHMQLf WJjBmhc9PvQg/stAZ7HXzF7r1+hNlSc= X-Google-Smtp-Source: AA6agR6No4qSdL/nDd/0M/rTal3kQSdp4Ji8I6l3Cmv9FqKfhz9O0qKyM3oceI9zq0i+RbuKrnfcvQ== X-Received: by 2002:a7b:ce05:0:b0:3a5:c069:25b3 with SMTP id m5-20020a7bce05000000b003a5c06925b3mr5077226wmc.87.1661342466477; Wed, 24 Aug 2022 05:01:06 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.01.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:01:05 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 25/37] gccrs: Add privacy checks Date: Wed, 24 Aug 2022 12:59:44 +0100 Message-Id: <20220824115956.737931-26-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: Arthur Cohen , gcc-rust@gcc.gnu.org Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Arthur Cohen This pass is responsible for resolving the privacy of items and verifying that access to these items is performed within the limits of that privacy. By default, items in Rust are private and only public to the current module and its submodules. However, the user can annotate an item with various qualifiers such as `pub` to publicly expose an item. Furthermore, a module path can be given to `pub` to restrict an item's privacy to a certain module: These paths need to be resolved and later on checked by the privacy error reporter. --- .../errors/privacy/rust-privacy-check.cc | 63 ++ .../errors/privacy/rust-privacy-check.h | 44 + .../errors/privacy/rust-privacy-common.h | 67 ++ .../checks/errors/privacy/rust-privacy-ctx.cc | 93 +++ .../checks/errors/privacy/rust-privacy-ctx.h | 79 ++ .../errors/privacy/rust-privacy-reporter.cc | 753 ++++++++++++++++++ .../errors/privacy/rust-privacy-reporter.h | 173 ++++ .../privacy/rust-pub-restricted-visitor.cc | 182 +++++ .../privacy/rust-pub-restricted-visitor.h | 120 +++ .../errors/privacy/rust-reachability.cc | 236 ++++++ .../checks/errors/privacy/rust-reachability.h | 87 ++ .../privacy/rust-visibility-resolver.cc | 245 ++++++ .../errors/privacy/rust-visibility-resolver.h | 103 +++ 13 files changed, 2245 insertions(+) create mode 100644 gcc/rust/checks/errors/privacy/rust-privacy-check.cc create mode 100644 gcc/rust/checks/errors/privacy/rust-privacy-check.h create mode 100644 gcc/rust/checks/errors/privacy/rust-privacy-common.h create mode 100644 gcc/rust/checks/errors/privacy/rust-privacy-ctx.cc create mode 100644 gcc/rust/checks/errors/privacy/rust-privacy-ctx.h create mode 100644 gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc create mode 100644 gcc/rust/checks/errors/privacy/rust-privacy-reporter.h create mode 100644 gcc/rust/checks/errors/privacy/rust-pub-restricted-visitor.cc create mode 100644 gcc/rust/checks/errors/privacy/rust-pub-restricted-visitor.h create mode 100644 gcc/rust/checks/errors/privacy/rust-reachability.cc create mode 100644 gcc/rust/checks/errors/privacy/rust-reachability.h create mode 100644 gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc create mode 100644 gcc/rust/checks/errors/privacy/rust-visibility-resolver.h diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-check.cc b/gcc/rust/checks/errors/privacy/rust-privacy-check.cc new file mode 100644 index 00000000000..9664d62f65c --- /dev/null +++ b/gcc/rust/checks/errors/privacy/rust-privacy-check.cc @@ -0,0 +1,63 @@ +// 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 +// . + +#include "rust-privacy-check.h" +#include "rust-reachability.h" +#include "rust-hir-type-check.h" +#include "rust-hir-map.h" +#include "rust-name-resolver.h" +#include "rust-visibility-resolver.h" +#include "rust-pub-restricted-visitor.h" +#include "rust-privacy-reporter.h" + +extern bool +saw_errors (void); + +namespace Rust { +namespace Privacy { + +void +Resolver::resolve (HIR::Crate &crate) +{ + PrivacyContext ctx; + auto mappings = Analysis::Mappings::get (); + auto resolver = Rust::Resolver::Resolver::get (); + auto ty_ctx = ::Rust::Resolver::TypeCheckContext::get (); + + VisibilityResolver (*mappings, *resolver).go (crate); + PubRestrictedVisitor (*mappings).go (crate); + PrivacyReporter (*mappings, *resolver, *ty_ctx).go (crate); + + auto visitor = ReachabilityVisitor (ctx, *ty_ctx); + + const auto &items = crate.items; + + for (auto &item : items) + { + if (item->get_hir_kind () == HIR::Node::VIS_ITEM) + { + auto vis_item = static_cast (item.get ()); + vis_item->accept_vis (visitor); + } + } + + if (saw_errors ()) + return; +} +} // namespace Privacy +} // namespace Rust diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-check.h b/gcc/rust/checks/errors/privacy/rust-privacy-check.h new file mode 100644 index 00000000000..290b5eacb6c --- /dev/null +++ b/gcc/rust/checks/errors/privacy/rust-privacy-check.h @@ -0,0 +1,44 @@ +// 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_PRIVACY_CHECK_H +#define RUST_PRIVACY_CHECK_H + +#include "rust-hir.h" +#include "rust-hir-expr.h" +#include "rust-hir-stmt.h" +#include "rust-hir-item.h" +#include "rust-hir-type-check.h" + +namespace Rust { +namespace Privacy { +class Resolver +{ +public: + /** + * Perform the full privacy resolving pass on a crate. + * + * This resolver first computes the reachability of all items in a crate, + * before checking for privacy violations. + */ + static void resolve (HIR::Crate &crate); +}; +} // namespace Privacy +} // namespace Rust + +#endif // !RUST_PRIVACY_CHECK_H diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-common.h b/gcc/rust/checks/errors/privacy/rust-privacy-common.h new file mode 100644 index 00000000000..ceafe91d886 --- /dev/null +++ b/gcc/rust/checks/errors/privacy/rust-privacy-common.h @@ -0,0 +1,67 @@ +// 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 +// . + +#include "rust-mapping-common.h" + +namespace Rust { +namespace Privacy { + +/** + * Visibility class related specifically to DefIds. This class allows defining + * the visibility of an item with regard to a specific module. + * + * Items are either public throughout a crate, or restricted to a specific + * module. Private items are simply restricted to the current module. + */ +class ModuleVisibility +{ +public: + enum Type + { + Unknown, + Public, + Restricted, + }; + + ModuleVisibility () : kind (Unknown), module_id (UNKNOWN_DEFID) {} + + static ModuleVisibility create_restricted (DefId module_id) + { + return ModuleVisibility (Type::Restricted, module_id); + } + + static ModuleVisibility create_public () + { + return ModuleVisibility (Type::Public, UNKNOWN_DEFID); + } + + Type get_kind () const { return kind; } + + const DefId &get_module_id () const { return module_id; } + DefId &get_module_id () { return module_id; } + +private: + ModuleVisibility (Type kind, DefId module_id) + : kind (kind), module_id (module_id) + {} + + Type kind; + DefId module_id; +}; +} // namespace Privacy +} // namespace Rust diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-ctx.cc b/gcc/rust/checks/errors/privacy/rust-privacy-ctx.cc new file mode 100644 index 00000000000..9ebc86988e9 --- /dev/null +++ b/gcc/rust/checks/errors/privacy/rust-privacy-ctx.cc @@ -0,0 +1,93 @@ +// 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 +// . + +#include "rust-privacy-ctx.h" +#include "selftest.h" + +namespace Rust { +namespace Privacy { + +static ReachLevel +insert_if_higher (ReachLevel new_level, + std::unordered_map::iterator &existing) +{ + if (new_level > existing->second) + existing->second = new_level; + + return existing->second; +} + +ReachLevel +PrivacyContext::update_reachability (const Analysis::NodeMapping &mapping, + ReachLevel reach) +{ + auto def_id = mapping.get_defid (); + auto existing_reach = reachability_map.find (def_id); + if (existing_reach != reachability_map.end ()) + return insert_if_higher (reach, existing_reach); + + reachability_map.insert ({def_id, reach}); + return reach; +} + +const ReachLevel * +PrivacyContext::lookup_reachability (const Analysis::NodeMapping &mapping) +{ + auto existing_reach = reachability_map.find (mapping.get_defid ()); + if (existing_reach == reachability_map.end ()) + return nullptr; + + return &existing_reach->second; +} +} // namespace Privacy +} // namespace Rust + +#if CHECKING_P +namespace selftest { +static void +update_reachability_test (void) +{ + auto ctx = Rust::Privacy::PrivacyContext (); + // Bogus values for the mappings + auto mapping = Rust::Analysis::NodeMapping (15, 15, 15, 15); + + auto new_level + = ctx.update_reachability (mapping, Rust::Privacy::ReachLevel::Unreachable); + + ASSERT_EQ (new_level, Rust::Privacy::ReachLevel::Unreachable); + + ASSERT_TRUE (ctx.lookup_reachability (mapping)); + ASSERT_EQ (*ctx.lookup_reachability (mapping), + Rust::Privacy::ReachLevel::Unreachable); + + new_level + = ctx.update_reachability (mapping, Rust::Privacy::ReachLevel::Reachable); + + ASSERT_EQ (new_level, Rust::Privacy::ReachLevel::Reachable); + ASSERT_TRUE (ctx.lookup_reachability (mapping)); + ASSERT_EQ (*ctx.lookup_reachability (mapping), + Rust::Privacy::ReachLevel::Reachable); +} + +void +rust_privacy_ctx_test (void) +{ + update_reachability_test (); +} +} // namespace selftest +#endif // !CHECKING_P diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-ctx.h b/gcc/rust/checks/errors/privacy/rust-privacy-ctx.h new file mode 100644 index 00000000000..52d790edf63 --- /dev/null +++ b/gcc/rust/checks/errors/privacy/rust-privacy-ctx.h @@ -0,0 +1,79 @@ +// 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_PRIVACY_CTX_H +#define RUST_PRIVACY_CTX_H + +#include "rust-hir-map.h" +#include "rust-privacy-check.h" + +namespace Rust { +namespace Privacy { + +/** + * Reachability levels of HIR nodes. These levels are computed through the + * `ReachabilityVisitor` visitor. + */ +enum ReachLevel +{ + Unreachable, + Reachable, +}; + +class PrivacyContext +{ +public: + /** + * Insert a new resolved visibility for a given node. If the node is already + * present in the reachability map, then its visibility will only be updated + * if the given visibility is higher. + * + * @param mappings Mappings of the node to store the reach level for + * @param reach Level of reachability for the given node + * + * @return The new reachability level for this node. If this was the first + * time inserting this node, then return `reach`. Otherwise, return `reach` or + * the existing reach level if it was higher. + */ + ReachLevel update_reachability (const Analysis::NodeMapping &mapping, + ReachLevel reach); + + /** + * Lookup the visibility of an already declared Node + * + * @param mapping Mappings of the node to fetch the reach level of + * + * @return `nullptr` if the reach level for the current node has not been + * added, a valid pointer otherwise + */ + const ReachLevel *lookup_reachability (const Analysis::NodeMapping &mapping); + +private: + std::unordered_map reachability_map; +}; +} // namespace Privacy +} // namespace Rust + +#if CHECKING_P +namespace selftest { +void +rust_privacy_ctx_test (void); +} +#endif // !CHECKING_P + +#endif // !RUST_PRIVACY_CTX_H diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc new file mode 100644 index 00000000000..35fde40782e --- /dev/null +++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc @@ -0,0 +1,753 @@ +#include "rust-privacy-reporter.h" +#include "rust-hir-expr.h" +#include "rust-hir-stmt.h" +#include "rust-hir-item.h" + +namespace Rust { +namespace Privacy { + +PrivacyReporter::PrivacyReporter ( + Analysis::Mappings &mappings, Resolver::Resolver &resolver, + const Rust::Resolver::TypeCheckContext &ty_ctx) + : mappings (mappings), resolver (resolver), ty_ctx (ty_ctx), + current_module (Optional::none ()) +{} + +void +PrivacyReporter::go (HIR::Crate &crate) +{ + for (auto &item : crate.items) + item->accept_vis (*this); +} + +static bool +is_child_module (Analysis::Mappings &mappings, NodeId parent, + NodeId possible_child) +{ + auto children = mappings.lookup_module_children (parent); + + if (!children) + return false; + + // Visit all toplevel children + for (auto &child : *children) + if (child == possible_child) + return true; + + // Now descend recursively in the child module tree + for (auto &child : *children) + if (is_child_module (mappings, child, possible_child)) + return true; + + return false; +} + +// FIXME: This function needs a lot of refactoring +void +PrivacyReporter::check_for_privacy_violation (const NodeId &use_id, + const Location &locus) +{ + NodeId ref_node_id = UNKNOWN_NODEID; + + // FIXME: Don't assert here - we might be dealing with a type + if (!resolver.lookup_resolved_name (use_id, &ref_node_id)) + resolver.lookup_resolved_type (use_id, &ref_node_id); + + // FIXME: Assert here. For now, we return since this causes issues when + // checking inferred types (#1260) + // rust_assert (ref_node_id != UNKNOWN_NODEID); + if (ref_node_id == UNKNOWN_NODEID) + return; + + ModuleVisibility vis; + + // FIXME: Can we really return here if the item has no visibility? + if (!mappings.lookup_visibility (ref_node_id, vis)) + return; + + auto valid = true; + + switch (vis.get_kind ()) + { + case ModuleVisibility::Public: + break; + case ModuleVisibility::Restricted: { + // If we are in the crate, everything is restricted correctly, but we + // can't get a module for it + if (current_module.is_none ()) + return; + + auto module = mappings.lookup_defid (vis.get_module_id ()); + rust_assert (module != nullptr); + + auto mod_node_id = module->get_mappings ().get_nodeid (); + + // We are in the module referenced by the pub(restricted) visibility. + // This is valid + if (mod_node_id == current_module.get ()) + break; + + // FIXME: This needs a LOT of TLC: hinting about the definition, a + // string to say if it's a module, function, type, etc... + if (!is_child_module (mappings, mod_node_id, current_module.get ())) + valid = false; + } + break; + case ModuleVisibility::Unknown: + rust_unreachable (); + break; + } + + if (!valid) + rust_error_at (locus, "definition is private in this context"); +} + +void +PrivacyReporter::check_base_type_privacy (Analysis::NodeMapping &node_mappings, + const TyTy::BaseType *ty, + const Location &locus) +{ + // Avoids repeating commong argument such as `use_id` or `locus` since we're + // doing a lot of recursive calls here + auto recursive_check + = [this, &node_mappings, &locus] (const TyTy::BaseType *ty) { + return check_base_type_privacy (node_mappings, ty, locus); + }; + + switch (ty->get_kind ()) + { + // These "simple" types are our stop condition + case TyTy::BOOL: + case TyTy::CHAR: + case TyTy::INT: + case TyTy::UINT: + case TyTy::FLOAT: + case TyTy::USIZE: + case TyTy::ISIZE: + case TyTy::ADT: + case TyTy::STR: { + auto ref_id = ty->get_ref (); + NodeId lookup_id; + + bool ok = mappings.lookup_hir_to_node (ref_id, &lookup_id); + rust_assert (ok); + + return check_for_privacy_violation (lookup_id, locus); + } + case TyTy::REF: + return recursive_check ( + static_cast (ty)->get_base ()); + case TyTy::POINTER: + return recursive_check ( + static_cast (ty)->get_base ()); + case TyTy::ARRAY: + return recursive_check ( + static_cast (ty)->get_element_type ()); + case TyTy::SLICE: + return recursive_check ( + static_cast (ty)->get_element_type ()); + case TyTy::FNPTR: + for (auto ¶m : static_cast (ty)->get_params ()) + recursive_check (param.get_tyty ()); + return recursive_check ( + static_cast (ty)->get_return_type ()); + case TyTy::TUPLE: + for (auto ¶m : + static_cast (ty)->get_fields ()) + recursive_check (param.get_tyty ()); + return; + case TyTy::PLACEHOLDER: + return recursive_check ( + // FIXME: Can we use `resolve` here? Is that what we should do? + static_cast (ty)->resolve ()); + case TyTy::PROJECTION: + return recursive_check ( + static_cast (ty)->get ()); + case TyTy::CLOSURE: + rust_sorry_at (locus, "privacy pass for closures is not handled yet"); + break; + + // If we're dealing with a generic param, there's nothing we should be + // doing here + case TyTy::PARAM: + // We are dealing with a function definition that has been assigned + // somewhere else. Nothing to resolve privacy-wise other than the actual + // function, which is resolved as an expression + case TyTy::FNDEF: + // FIXME: Can we really not resolve Dynamic types here? Shouldn't we have + // a look at the path and perform proper privacy analysis? + case TyTy::DYNAMIC: + // The never type is builtin and always available + case TyTy::NEVER: + // We shouldn't have inference types here, ever + case TyTy::INFER: + return; + case TyTy::ERROR: + rust_unreachable (); + } +} + +void +PrivacyReporter::check_type_privacy (const HIR::Type *type) +{ + rust_assert (type); + + TyTy::BaseType *lookup = nullptr; + rust_assert ( + ty_ctx.lookup_type (type->get_mappings ().get_hirid (), &lookup)); + + auto node_mappings = type->get_mappings (); + return check_base_type_privacy (node_mappings, lookup, type->get_locus ()); +} + +void +PrivacyReporter::visit (HIR::PathInExpression &path) +{ + check_for_privacy_violation (path.get_mappings ().get_nodeid (), + path.get_locus ()); +} + +void +PrivacyReporter::visit (HIR::TypePathSegmentFunction &segment) +{ + // FIXME: Do we need to do anything for this? +} + +void +PrivacyReporter::visit (HIR::TypePath &path) +{ + check_for_privacy_violation (path.get_mappings ().get_nodeid (), + path.get_locus ()); +} + +void +PrivacyReporter::visit (HIR::QualifiedPathInExpression &path) +{ + check_for_privacy_violation (path.get_mappings ().get_nodeid (), + path.get_locus ()); +} + +void +PrivacyReporter::visit (HIR::QualifiedPathInType &path) +{ + check_for_privacy_violation (path.get_mappings ().get_nodeid (), + path.get_locus ()); +} + +void +PrivacyReporter::visit (HIR::LiteralExpr &expr) +{ + // Literals cannot contain any sort of privacy violation +} + +void +PrivacyReporter::visit (HIR::BorrowExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::DereferenceExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::ErrorPropagationExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::NegationExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::ArithmeticOrLogicalExpr &expr) +{ + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::ComparisonExpr &expr) +{ + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::LazyBooleanExpr &expr) +{ + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::TypeCastExpr &expr) +{ + expr.get_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::AssignmentExpr &expr) +{ + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::CompoundAssignmentExpr &expr) +{ + expr.get_left_expr ()->accept_vis (*this); + expr.get_right_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::GroupedExpr &expr) +{ + expr.get_expr_in_parens ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::ArrayExpr &expr) +{ + HIR::ArrayElems &elements = *expr.get_internal_elements (); + switch (elements.get_array_expr_type ()) + { + case HIR::ArrayElems::ArrayExprType::VALUES: { + HIR::ArrayElemsValues &elems + = static_cast (elements); + for (auto &value : elems.get_values ()) + value->accept_vis (*this); + } + return; + + case HIR::ArrayElems::ArrayExprType::COPIED: + HIR::ArrayElemsCopied &elems + = static_cast (elements); + elems.get_elem_to_copy ()->accept_vis (*this); + } +} + +void +PrivacyReporter::visit (HIR::ArrayIndexExpr &expr) +{ + expr.get_array_expr ()->accept_vis (*this); + expr.get_index_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::TupleExpr &expr) +{ + for (auto &value : expr.get_tuple_elems ()) + value->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::TupleIndexExpr &expr) +{ + expr.get_tuple_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::StructExprStruct &expr) +{ + // FIXME: We need to check the visibility of the type it refers to here +} + +void +PrivacyReporter::visit (HIR::StructExprFieldIdentifier &field) +{} + +void +PrivacyReporter::visit (HIR::StructExprFieldIdentifierValue &field) +{ + field.get_value ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::StructExprFieldIndexValue &field) +{ + field.get_value ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::StructExprStructFields &expr) +{ + for (auto &field : expr.get_fields ()) + field->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::CallExpr &expr) +{ + expr.get_fnexpr ()->accept_vis (*this); + + for (auto ¶m : expr.get_arguments ()) + param->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::MethodCallExpr &expr) +{ + expr.get_receiver ()->accept_vis (*this); + + for (auto ¶m : expr.get_arguments ()) + param->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::FieldAccessExpr &expr) +{ + expr.get_receiver_expr ()->accept_vis (*this); + + // FIXME: We should also check if the field is public? +} + +void +PrivacyReporter::visit (HIR::ClosureExprInner &expr) +{ + // Not handled yet +} + +void +PrivacyReporter::visit (HIR::BlockExpr &expr) +{ + for (auto &stmt : expr.get_statements ()) + stmt->accept_vis (*this); + + auto &last_expr = expr.get_final_expr (); + if (last_expr) + last_expr->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::ClosureExprInnerTyped &expr) +{ + // Not handled yet +} + +void +PrivacyReporter::visit (HIR::ContinueExpr &expr) +{} + +void +PrivacyReporter::visit (HIR::BreakExpr &expr) +{ + auto &break_expr = expr.get_expr (); + if (break_expr) + break_expr->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::RangeFromToExpr &expr) +{ + expr.get_from_expr ()->accept_vis (*this); + expr.get_to_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::RangeFromExpr &expr) +{ + expr.get_from_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::RangeToExpr &expr) +{ + expr.get_to_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::RangeFullExpr &expr) +{} + +void +PrivacyReporter::visit (HIR::RangeFromToInclExpr &expr) +{ + expr.get_from_expr ()->accept_vis (*this); + expr.get_to_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::RangeToInclExpr &expr) +{ + // Not handled yet +} + +void +PrivacyReporter::visit (HIR::ReturnExpr &expr) +{ + auto return_expr = expr.get_expr (); + if (return_expr) + return_expr->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::UnsafeBlockExpr &expr) +{ + expr.get_block_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::LoopExpr &expr) +{ + expr.get_loop_block ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::WhileLoopExpr &expr) +{ + expr.get_predicate_expr ()->accept_vis (*this); + expr.get_loop_block ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::WhileLetLoopExpr &expr) +{ + expr.get_cond ()->accept_vis (*this); + expr.get_loop_block ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::ForLoopExpr &expr) +{ + expr.get_iterator_expr ()->accept_vis (*this); + expr.get_loop_block ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::IfExpr &expr) +{ + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::IfExprConseqElse &expr) +{ + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + expr.get_else_block ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::IfExprConseqIf &expr) +{ + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + expr.get_conseq_if_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::IfExprConseqIfLet &expr) +{ + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + + // TODO: We need to visit the if_let_expr as well +} + +void +PrivacyReporter::visit (HIR::IfLetExpr &expr) +{ + // TODO: We need to visit the if_let_expr + // TODO: We need to visit the block as well +} + +void +PrivacyReporter::visit (HIR::IfLetExprConseqElse &expr) +{ + // TODO: We need to visit the if_let_expr + // TODO: We need to visit the if_block as well + // TODO: We need to visit the else_block as well +} + +void +PrivacyReporter::visit (HIR::IfLetExprConseqIf &expr) +{ + // TODO: We need to visit the if_let_expr + // TODO: We need to visit the if_block as well + // TODO: We need to visit the else_block as well +} + +void +PrivacyReporter::visit (HIR::IfLetExprConseqIfLet &expr) +{ + // TODO: We need to visit the if_let_expr + // TODO: We need to visit the if_block as well + // TODO: We need to visit the else_block as well +} + +void +PrivacyReporter::visit (HIR::MatchExpr &expr) +{ + expr.get_scrutinee_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::AwaitExpr &expr) +{ + // Not handled yet +} + +void +PrivacyReporter::visit (HIR::AsyncBlockExpr &expr) +{ + // Not handled yet +} + +void +PrivacyReporter::visit (HIR::Module &module) +{ + // FIXME: We also need to think about module privacy + + auto old_module = current_module; + current_module + = Optional::some (module.get_mappings ().get_nodeid ()); + + for (auto &item : module.get_items ()) + item->accept_vis (*this); + + current_module = old_module; +} + +void +PrivacyReporter::visit (HIR::ExternCrate &crate) +{} + +void +PrivacyReporter::visit (HIR::UseDeclaration &use_decl) +{ + // FIXME: Is there anything we need to do here? +} + +void +PrivacyReporter::visit (HIR::Function &function) +{ + for (auto ¶m : function.get_function_params ()) + check_type_privacy (param.get_type ()); + + function.get_definition ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::TypeAlias &type_alias) +{ + // TODO: Check the type here +} + +void +PrivacyReporter::visit (HIR::StructStruct &struct_item) +{ + // TODO: Check the type of all fields +} + +void +PrivacyReporter::visit (HIR::TupleStruct &tuple_struct) +{ + // TODO: Check the type of all fields +} + +void +PrivacyReporter::visit (HIR::EnumItem &item) +{ + // TODO: Check the type of all variants +} + +void +PrivacyReporter::visit (HIR::EnumItemTuple &item) +{ + // TODO: Check the type +} + +void +PrivacyReporter::visit (HIR::EnumItemStruct &item) +{ + // TODO: Check the type +} + +void +PrivacyReporter::visit (HIR::EnumItemDiscriminant &item) +{} + +void +PrivacyReporter::visit (HIR::Enum &enum_item) +{} + +void +PrivacyReporter::visit (HIR::Union &union_item) +{ + // TODO: Check the type +} + +void +PrivacyReporter::visit (HIR::ConstantItem &const_item) +{ + // TODO: We need to visit the type + const_item.get_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::StaticItem &static_item) +{ + // TODO: We need to visit the type + static_item.get_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::Trait &trait) +{ + // FIXME: We need to be an ItemVisitor as well + // for (auto &item : trait.get_trait_items ()) + // item->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::ImplBlock &impl) +{ + for (auto &item : impl.get_impl_items ()) + item->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::ExternBlock &block) +{ + // FIXME: We need to be an ItemVisitor as well + // for (auto &item : block.get_extern_items ()) + // item->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::EmptyStmt &stmt) +{} + +void +PrivacyReporter::visit (HIR::LetStmt &stmt) +{ + auto type = stmt.get_type (); + if (type) + check_type_privacy (type); + + auto init_expr = stmt.get_init_expr (); + if (init_expr) + init_expr->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::ExprStmtWithoutBlock &stmt) +{ + stmt.get_expr ()->accept_vis (*this); +} + +void +PrivacyReporter::visit (HIR::ExprStmtWithBlock &stmt) +{ + stmt.get_expr ()->accept_vis (*this); +} + +} // namespace Privacy +} // namespace Rust diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h new file mode 100644 index 00000000000..546b108f36d --- /dev/null +++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h @@ -0,0 +1,173 @@ +// 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_PRIVACY_REPORTER_H +#define RUST_PRIVACY_REPORTER_H + +#include "rust-hir-map.h" +#include "rust-hir-visitor.h" +#include "rust-mapping-common.h" +#include "rust-name-resolver.h" + +namespace Rust { +namespace Privacy { + +/** + * This visitor visits all items and expressions of a crate and reports privacy + * violations. It should be started after using the `VisibilityResolver` visitor + * which resolves the visibilities of all items of a crate. + */ +class PrivacyReporter : public HIR::HIRExpressionVisitor, + public HIR::HIRStmtVisitor +{ +public: + PrivacyReporter (Analysis::Mappings &mappings, + Rust::Resolver::Resolver &resolver, + const Rust::Resolver::TypeCheckContext &ty_ctx); + + /** + * Perform privacy error reporting on an entire crate + */ + void go (HIR::Crate &crate); + +private: + /** + * Check if a given item's visibility is accessible from the current module. + * + * This function reports the errors it finds. + * + * @param use_id NodeId of the expression/statement referencing an item with + * a visibility + * @param locus Location of said expression/statement + */ + void check_for_privacy_violation (const NodeId &use_id, + const Location &locus); + + /** + * Internal function used by `check_type_privacy` when dealing with complex +types + * such as references or arrays + */ + void check_base_type_privacy (Analysis::NodeMapping &node_mappings, + const TyTy::BaseType *ty, + const Location &locus); + + /** + * Check the privacy of an explicit type. + * + * This function reports the errors it finds. + * + * @param type Reference to an explicit type used in a statement, expression + * or parameter + */ + void check_type_privacy (const HIR::Type *type); + + virtual void visit (HIR::StructExprFieldIdentifier &field); + virtual void visit (HIR::StructExprFieldIdentifierValue &field); + virtual void visit (HIR::StructExprFieldIndexValue &field); + + virtual void visit (HIR::QualifiedPathInExpression &expr); + virtual void visit (HIR::PathInExpression &expr); + virtual void visit (HIR::ClosureExprInnerTyped &); + virtual void visit (HIR::ClosureExprInner &expr); + virtual void visit (HIR::StructExprStructFields &); + virtual void visit (HIR::StructExprStruct &); + virtual void visit (HIR::LiteralExpr &expr); + virtual void visit (HIR::BorrowExpr &expr); + virtual void visit (HIR::DereferenceExpr &expr); + virtual void visit (HIR::ErrorPropagationExpr &expr); + virtual void visit (HIR::NegationExpr &expr); + virtual void visit (HIR::ArithmeticOrLogicalExpr &expr); + virtual void visit (HIR::ComparisonExpr &expr); + virtual void visit (HIR::LazyBooleanExpr &expr); + virtual void visit (HIR::TypeCastExpr &expr); + virtual void visit (HIR::AssignmentExpr &expr); + virtual void visit (HIR::CompoundAssignmentExpr &expr); + virtual void visit (HIR::GroupedExpr &expr); + virtual void visit (HIR::ArrayExpr &expr); + virtual void visit (HIR::ArrayIndexExpr &expr); + virtual void visit (HIR::TupleExpr &expr); + virtual void visit (HIR::TupleIndexExpr &expr); + virtual void visit (HIR::CallExpr &expr); + virtual void visit (HIR::MethodCallExpr &expr); + virtual void visit (HIR::FieldAccessExpr &expr); + virtual void visit (HIR::BlockExpr &expr); + virtual void visit (HIR::ContinueExpr &expr); + virtual void visit (HIR::BreakExpr &expr); + virtual void visit (HIR::RangeFromToExpr &expr); + virtual void visit (HIR::RangeFromExpr &expr); + virtual void visit (HIR::RangeToExpr &expr); + virtual void visit (HIR::RangeFullExpr &expr); + virtual void visit (HIR::RangeFromToInclExpr &expr); + virtual void visit (HIR::RangeToInclExpr &expr); + virtual void visit (HIR::ReturnExpr &expr); + virtual void visit (HIR::UnsafeBlockExpr &expr); + virtual void visit (HIR::LoopExpr &expr); + virtual void visit (HIR::WhileLoopExpr &expr); + virtual void visit (HIR::WhileLetLoopExpr &expr); + virtual void visit (HIR::ForLoopExpr &expr); + virtual void visit (HIR::IfExpr &expr); + virtual void visit (HIR::IfExprConseqElse &expr); + virtual void visit (HIR::IfExprConseqIf &expr); + virtual void visit (HIR::IfExprConseqIfLet &expr); + virtual void visit (HIR::IfLetExpr &expr); + virtual void visit (HIR::IfLetExprConseqElse &expr); + virtual void visit (HIR::IfLetExprConseqIf &expr); + virtual void visit (HIR::IfLetExprConseqIfLet &expr); + virtual void visit (HIR::MatchExpr &expr); + virtual void visit (HIR::AwaitExpr &expr); + virtual void visit (HIR::AsyncBlockExpr &expr); + + virtual void visit (HIR::EnumItemTuple &); + virtual void visit (HIR::EnumItemStruct &); + virtual void visit (HIR::EnumItem &item); + virtual void visit (HIR::TupleStruct &tuple_struct); + virtual void visit (HIR::EnumItemDiscriminant &); + virtual void visit (HIR::TypePathSegmentFunction &segment); + virtual void visit (HIR::TypePath &path); + virtual void visit (HIR::QualifiedPathInType &path); + virtual void visit (HIR::Module &module); + virtual void visit (HIR::ExternCrate &crate); + virtual void visit (HIR::UseDeclaration &use_decl); + virtual void visit (HIR::Function &function); + virtual void visit (HIR::TypeAlias &type_alias); + virtual void visit (HIR::StructStruct &struct_item); + virtual void visit (HIR::Enum &enum_item); + virtual void visit (HIR::Union &union_item); + virtual void visit (HIR::ConstantItem &const_item); + virtual void visit (HIR::StaticItem &static_item); + virtual void visit (HIR::Trait &trait); + virtual void visit (HIR::ImplBlock &impl); + virtual void visit (HIR::ExternBlock &block); + virtual void visit (HIR::EmptyStmt &stmt); + virtual void visit (HIR::LetStmt &stmt); + virtual void visit (HIR::ExprStmtWithoutBlock &stmt); + virtual void visit (HIR::ExprStmtWithBlock &stmt); + + Analysis::Mappings &mappings; + Rust::Resolver::Resolver &resolver; + const Rust::Resolver::TypeCheckContext &ty_ctx; + + // `None` means we're in the root module - the crate + Optional current_module; +}; + +} // namespace Privacy +} // namespace Rust + +#endif // !RUST_PRIVACY_REPORTER_H diff --git a/gcc/rust/checks/errors/privacy/rust-pub-restricted-visitor.cc b/gcc/rust/checks/errors/privacy/rust-pub-restricted-visitor.cc new file mode 100644 index 00000000000..e391653ea26 --- /dev/null +++ b/gcc/rust/checks/errors/privacy/rust-pub-restricted-visitor.cc @@ -0,0 +1,182 @@ +// 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 +// . + +#include "rust-pub-restricted-visitor.h" +#include "rust-hir.h" +#include "rust-hir-item.h" + +namespace Rust { +namespace Privacy { + +bool +PubRestrictedVisitor::is_restriction_valid (NodeId item_id, + const Location &locus) +{ + ModuleVisibility visibility; + + // If there is no visibility in the mappings, then the item is private and + // does not contain any restriction + // FIXME: Is that correct? + if (!mappings.lookup_visibility (item_id, visibility)) + return true; + + for (auto mod = module_stack.rbegin (); mod != module_stack.rend (); mod++) + if (*mod == visibility.get_module_id ()) + return true; + + rust_error_at (locus, "restricted path is not an ancestor of the " + "current module"); + return false; +} + +PubRestrictedVisitor::PubRestrictedVisitor (Analysis::Mappings &mappings) + : mappings (mappings) +{} + +void +PubRestrictedVisitor::go (HIR::Crate &crate) +{ + // The `crate` module will always be present + module_stack.emplace_back (crate.get_mappings ().get_defid ()); + + // FIXME: When do we insert `super`? `self`? + // We need wrapper function for these + + for (auto &item : crate.items) + { + if (item->get_hir_kind () == HIR::Node::VIS_ITEM) + { + auto vis_item = static_cast (item.get ()); + vis_item->accept_vis (*this); + } + } +} + +void +PubRestrictedVisitor::visit (HIR::Module &mod) +{ + // FIXME: We need to update `super` and `self` here + module_stack.push_back (mod.get_mappings ().get_defid ()); + + is_restriction_valid (mod.get_mappings ().get_nodeid (), mod.get_locus ()); + + for (auto &item : mod.get_items ()) + { + if (item->get_hir_kind () == HIR::Node::VIS_ITEM) + { + auto vis_item = static_cast (item.get ()); + vis_item->accept_vis (*this); + } + } + + module_stack.pop_back (); +} + +void +PubRestrictedVisitor::visit (HIR::ExternCrate &crate) +{ + is_restriction_valid (crate.get_mappings ().get_nodeid (), + crate.get_locus ()); +} + +void +PubRestrictedVisitor::visit (HIR::UseDeclaration &use_decl) +{ + is_restriction_valid (use_decl.get_mappings ().get_nodeid (), + use_decl.get_locus ()); +} + +void +PubRestrictedVisitor::visit (HIR::Function &func) +{ + is_restriction_valid (func.get_mappings ().get_nodeid (), func.get_locus ()); +} + +void +PubRestrictedVisitor::visit (HIR::TypeAlias &type_alias) +{ + is_restriction_valid (type_alias.get_mappings ().get_nodeid (), + type_alias.get_locus ()); +} + +void +PubRestrictedVisitor::visit (HIR::StructStruct &struct_item) +{ + is_restriction_valid (struct_item.get_mappings ().get_nodeid (), + struct_item.get_locus ()); + // FIXME: Check fields here as well +} + +void +PubRestrictedVisitor::visit (HIR::TupleStruct &tuple_struct) +{ + is_restriction_valid (tuple_struct.get_mappings ().get_nodeid (), + tuple_struct.get_locus ()); + // FIXME: Check fields here as well +} + +void +PubRestrictedVisitor::visit (HIR::Enum &enum_item) +{ + is_restriction_valid (enum_item.get_mappings ().get_nodeid (), + enum_item.get_locus ()); +} + +void +PubRestrictedVisitor::visit (HIR::Union &union_item) +{ + is_restriction_valid (union_item.get_mappings ().get_nodeid (), + union_item.get_locus ()); +} + +void +PubRestrictedVisitor::visit (HIR::ConstantItem &const_item) +{ + is_restriction_valid (const_item.get_mappings ().get_nodeid (), + const_item.get_locus ()); +} + +void +PubRestrictedVisitor::visit (HIR::StaticItem &static_item) +{ + is_restriction_valid (static_item.get_mappings ().get_nodeid (), + static_item.get_locus ()); +} + +void +PubRestrictedVisitor::visit (HIR::Trait &trait) +{ + is_restriction_valid (trait.get_mappings ().get_nodeid (), + trait.get_locus ()); +} + +void +PubRestrictedVisitor::visit (HIR::ImplBlock &impl) +{ + is_restriction_valid (impl.get_mappings ().get_nodeid (), impl.get_locus ()); +} + +void +PubRestrictedVisitor::visit (HIR::ExternBlock &block) +{ + is_restriction_valid (block.get_mappings ().get_nodeid (), + block.get_locus ()); +} + +} // namespace Privacy +} // namespace Rust diff --git a/gcc/rust/checks/errors/privacy/rust-pub-restricted-visitor.h b/gcc/rust/checks/errors/privacy/rust-pub-restricted-visitor.h new file mode 100644 index 00000000000..2685f3d1488 --- /dev/null +++ b/gcc/rust/checks/errors/privacy/rust-pub-restricted-visitor.h @@ -0,0 +1,120 @@ +// 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_PUB_RESTRICTED_VISITOR_H +#define RUST_PUB_RESTRICTED_VISITOR_H + +#include "rust-hir-visitor.h" +#include "rust-hir.h" +#include "rust-hir-expr.h" +#include "rust-hir-stmt.h" +#include "rust-hir-item.h" +#include "rust-hir-map.h" + +namespace Rust { +namespace Privacy { + +/** + * This visitor takes care of reporting `pub(restricted)` violations: + * A `pub(restricted)` violation is defined as the usage of a path restriction + * on an item which does not restrict the item's visibility to one of its parent + * modules. What this means is that an user is allowed to specify that an item + * should be public for any of its parent modules, going all the way to the + * `crate` module, but not for any of its children module. + * + * ```rust + * mod a { + * mod b { + * pub (in a) struct A0; + * + * mod c { + * mod d { + * pub (in a) struct A1; + * } + * } + * + * pub (in c::d) struct A2; + * } + * } + * ``` + * + * The above `A0`'s visibility is valid: It is restricted to a path, `a`, + * which is a parent of the current module, `b`. + * Likewise, `A1` is also defined properly: `a` is a parent of `d`, albeit + * a great-great-great-grandparant of it. + * + * `A2` visibility, however, is invalid: Where the struct is defined, the + * current module is `b`. `c::d` (which refers to the `d` module) is a child of + * `b`, and not one of its ancestors. + * + * Note that these resolution rules are also the ones of the 2015 rust edition: + * All the `pub(restricted)` visibilities above would be invalid in the 2018 + * edition, as the paths there must be absolute and not relative (`c::d` would + * become `crate::a::b::c::d` etc). Nonetheless, the logic stays the same. + */ +class PubRestrictedVisitor : public HIR::HIRVisItemVisitor +{ +public: + PubRestrictedVisitor (Analysis::Mappings &mappings); + + void go (HIR::Crate &crate); + + /** + * Check if an item's restricted visibility (`pub (crate)`, `pub (self)`, + * `pub(super)`, `pub (in )`) is valid in the current context. + * `pub restricted` visibilities are only allowed when the restriction path + * is a parent module of the item being visited. + * + * In case of error, this function will emit the errors and return. + * + * @param item_id NodeId of the item to check the restriction of + * @param locus Location of the item being checked + * + * @return true if the visibility restriction is valid, false otherwise. + */ + bool is_restriction_valid (NodeId item_id, const Location &locus); + + virtual void visit (HIR::Module &mod); + virtual void visit (HIR::ExternCrate &crate); + virtual void visit (HIR::UseDeclaration &use_decl); + virtual void visit (HIR::Function &func); + virtual void visit (HIR::TypeAlias &type_alias); + virtual void visit (HIR::StructStruct &struct_item); + virtual void visit (HIR::TupleStruct &tuple_struct); + virtual void visit (HIR::Enum &enum_item); + virtual void visit (HIR::Union &union_item); + virtual void visit (HIR::ConstantItem &const_item); + virtual void visit (HIR::StaticItem &static_item); + virtual void visit (HIR::Trait &trait); + virtual void visit (HIR::ImplBlock &impl); + virtual void visit (HIR::ExternBlock &block); + +private: + /* Stack of ancestor modules visited by this visitor */ + std::vector module_stack; + + // FIXME: Do we have to handle `self` and `super` as part of the name + // resolution pass? + + Analysis::Mappings &mappings; +}; + +} // namespace Privacy +} // namespace Rust + +#endif // !RUST_PUB_RESTRICTED_VISITOR_H diff --git a/gcc/rust/checks/errors/privacy/rust-reachability.cc b/gcc/rust/checks/errors/privacy/rust-reachability.cc new file mode 100644 index 00000000000..b322e29bfc3 --- /dev/null +++ b/gcc/rust/checks/errors/privacy/rust-reachability.cc @@ -0,0 +1,236 @@ +// 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 +// . + +#include "rust-reachability.h" +#include "rust-tyty.h" + +namespace Rust { +namespace Privacy { + +static HIR::VisItem * +maybe_get_vis_item (std::unique_ptr &item) +{ + if (item->get_hir_kind () != HIR::Node::VIS_ITEM) + return nullptr; + + return static_cast (item.get ()); +} + +ReachLevel +ReachabilityVisitor::get_reachability_level ( + const HIR::Visibility &item_visibility) +{ + return item_visibility.is_public () ? current_level : ReachLevel::Unreachable; +} + +void +ReachabilityVisitor::visit_generic_predicates ( + const std::vector> &generics, + ReachLevel item_reach) +{ + if (item_reach == ReachLevel::Unreachable) + return; + + for (const auto &generic : generics) + { + if (generic->get_kind () == HIR::GenericParam::GenericKind::TYPE) + { + TyTy::BaseType *generic_ty = nullptr; + auto ok = ty_ctx.lookup_type (generic->get_mappings ().get_hirid (), + &generic_ty); + rust_assert (ok); + rust_assert (generic_ty->get_kind () == TyTy::PARAM); + + auto generic_param = static_cast (generic_ty); + for (const auto &bound : generic_param->get_specified_bounds ()) + { + const auto trait = bound.get ()->get_hir_trait_ref (); + ctx.update_reachability (trait->get_mappings (), item_reach); + } + } + } +} + +void +ReachabilityVisitor::visit (HIR::Module &mod) +{ + auto reach = get_reachability_level (mod.get_visibility ()); + reach = ctx.update_reachability (mod.get_mappings (), reach); + + for (auto &item : mod.get_items ()) + { + // FIXME: Is that what we want to do? Yes? Only visit the items with + // visibility? + // + // Imagine if we had `maybe_get_vis_item(item)?->accept_vis(*this)` ;) + auto vis_item = maybe_get_vis_item (item); + if (vis_item) + vis_item->accept_vis (*this); + } +} + +void +ReachabilityVisitor::visit (HIR::ExternCrate &crate) +{ + auto reach = get_reachability_level (crate.get_visibility ()); + reach = ctx.update_reachability (crate.get_mappings (), reach); +} + +void +ReachabilityVisitor::visit (HIR::UseDeclaration &use_decl) +{ + auto reach = get_reachability_level (use_decl.get_visibility ()); + reach = ctx.update_reachability (use_decl.get_mappings (), reach); +} + +void +ReachabilityVisitor::visit (HIR::Function &func) +{ + auto fn_reach = get_reachability_level (func.get_visibility ()); + + fn_reach = ctx.update_reachability (func.get_mappings (), fn_reach); + visit_generic_predicates (func.get_generic_params (), fn_reach); +} + +void +ReachabilityVisitor::visit (HIR::TypeAlias &type_alias) +{ + auto type_reach = get_reachability_level (type_alias.get_visibility ()); + + visit_generic_predicates (type_alias.get_generic_params (), type_reach); +} + +void +ReachabilityVisitor::visit (HIR::StructStruct &struct_item) +{ + auto struct_reach = get_reachability_level (struct_item.get_visibility ()); + + struct_reach + = ctx.update_reachability (struct_item.get_mappings (), struct_reach); + + auto old_level = current_level; + current_level = struct_reach; + + visit_generic_predicates (struct_item.get_generic_params (), struct_reach); + + if (struct_reach != ReachLevel::Unreachable) + { + for (auto &field : struct_item.get_fields ()) + if (field.get_visibility ().is_public ()) + ctx.update_reachability (field.get_field_type ()->get_mappings (), + struct_reach); + } + + current_level = old_level; +} + +void +ReachabilityVisitor::visit (HIR::TupleStruct &tuple_struct) +{} + +void +ReachabilityVisitor::visit (HIR::Enum &enum_item) +{ + auto enum_reach = get_reachability_level (enum_item.get_visibility ()); + + enum_reach = ctx.update_reachability (enum_item.get_mappings (), enum_reach); + visit_generic_predicates (enum_item.get_generic_params (), enum_reach); + + for (const auto &variant : enum_item.get_variants ()) + { + auto variant_reach + = ctx.update_reachability (variant->get_mappings (), enum_reach); + + switch (variant->get_enum_item_kind ()) + { + case HIR::EnumItem::Tuple: { + // Should we update the fields only if they are public? Similarly to + // what we do in the ReachabilityVisitor for HIR::TupleStruct? + auto tuple_variant + = static_cast (variant.get ()); + for (const auto &field : tuple_variant->get_tuple_fields ()) + ctx.update_reachability (field.get_mappings (), variant_reach); + break; + } + case HIR::EnumItem::Struct: { + // Should we update the fields only if they are public? Similarly to + // what we do in the ReachabilityVisitor for HIR::StructStruct? + auto struct_variant + = static_cast (variant.get ()); + for (const auto &field : struct_variant->get_struct_fields ()) + ctx.update_reachability (field.get_mappings (), variant_reach); + break; + } + // Nothing nested to visit in that case + case HIR::EnumItem::Named: + case HIR::EnumItem::Discriminant: + break; + } + } +} + +void +ReachabilityVisitor::visit (HIR::Union &union_item) +{ + auto union_reach = get_reachability_level (union_item.get_visibility ()); + + union_reach + = ctx.update_reachability (union_item.get_mappings (), union_reach); + visit_generic_predicates (union_item.get_generic_params (), union_reach); +} + +void +ReachabilityVisitor::visit (HIR::ConstantItem &const_item) +{ + auto reach = get_reachability_level (const_item.get_visibility ()); + reach = ctx.update_reachability (const_item.get_mappings (), reach); +} + +void +ReachabilityVisitor::visit (HIR::StaticItem &static_item) +{ + auto reach = get_reachability_level (static_item.get_visibility ()); + reach = ctx.update_reachability (static_item.get_mappings (), reach); +} + +void +ReachabilityVisitor::visit (HIR::Trait &trait) +{ + auto trait_reach = get_reachability_level (trait.get_visibility ()); + + trait_reach = ctx.update_reachability (trait.get_mappings (), trait_reach); + visit_generic_predicates (trait.get_generic_params (), trait_reach); +} + +void +ReachabilityVisitor::visit (HIR::ImplBlock &impl) +{ + auto impl_reach = get_reachability_level (impl.get_visibility ()); + + impl_reach = ctx.update_reachability (impl.get_mappings (), impl_reach); + visit_generic_predicates (impl.get_generic_params (), impl_reach); +} + +void +ReachabilityVisitor::visit (HIR::ExternBlock &block) +{} + +// FIXME: How can we visit Blocks in the current configuration? Have a full +// visitor? +} // namespace Privacy +} // namespace Rust diff --git a/gcc/rust/checks/errors/privacy/rust-reachability.h b/gcc/rust/checks/errors/privacy/rust-reachability.h new file mode 100644 index 00000000000..e0bc4f5f0b8 --- /dev/null +++ b/gcc/rust/checks/errors/privacy/rust-reachability.h @@ -0,0 +1,87 @@ +// 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_REACHABILITY_H +#define RUST_REACHABILITY_H + +#include "rust-privacy-ctx.h" +#include "rust-hir-visitor.h" +#include "rust-hir.h" +#include "rust-hir-expr.h" +#include "rust-hir-stmt.h" +#include "rust-hir-item.h" +#include "rust-hir-type-check.h" + +namespace Rust { +namespace Privacy { + +// FIXME: The EmbargoVisitor from rustc is a fixed-point visitor which tries +// to reach more and more nodes until nothing has changed anymore. +// Do we need to reproduce this behavior? How long does it take to do this? + +/** + * The ReachabilityVisitor tries to reach all items possible in the crate, + * according to their privacy level. + */ +class ReachabilityVisitor : public HIR::HIRVisItemVisitor +{ +public: + ReachabilityVisitor (PrivacyContext &ctx, + const ::Rust::Resolver::TypeCheckContext &ty_ctx) + : current_level (ReachLevel::Reachable), ctx (ctx), ty_ctx (ty_ctx) + {} + + // FIXME: Add `go` method which takes an `HIR::Crate &` as argument + + /** + * Visit all the predicates of all the generic types of a given item, marking + * them as reachable or not. + */ + void visit_generic_predicates ( + const std::vector> &generics, + ReachLevel item_reach); + + /** + * Get the initial reach level for an item based on its visibility. + */ + ReachLevel get_reachability_level (const HIR::Visibility &item_visibility); + + virtual void visit (HIR::Module &mod); + virtual void visit (HIR::ExternCrate &crate); + virtual void visit (HIR::UseDeclaration &use_decl); + virtual void visit (HIR::Function &func); + virtual void visit (HIR::TypeAlias &type_alias); + virtual void visit (HIR::StructStruct &struct_item); + virtual void visit (HIR::TupleStruct &tuple_struct); + virtual void visit (HIR::Enum &enum_item); + virtual void visit (HIR::Union &union_item); + virtual void visit (HIR::ConstantItem &const_item); + virtual void visit (HIR::StaticItem &static_item); + virtual void visit (HIR::Trait &trait); + virtual void visit (HIR::ImplBlock &impl); + virtual void visit (HIR::ExternBlock &block); + +private: + ReachLevel current_level; + PrivacyContext &ctx; + const ::Rust::Resolver::TypeCheckContext &ty_ctx; +}; +} // namespace Privacy +} // namespace Rust + +#endif // !RUST_REACHABILITY_H diff --git a/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc b/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc new file mode 100644 index 00000000000..301182754a4 --- /dev/null +++ b/gcc/rust/checks/errors/privacy/rust-visibility-resolver.cc @@ -0,0 +1,245 @@ +// 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 +// . + +#include "rust-visibility-resolver.h" +#include "rust-ast.h" +#include "rust-hir.h" +#include "rust-hir-item.h" + +namespace Rust { +namespace Privacy { + +VisibilityResolver::VisibilityResolver (Analysis::Mappings &mappings, + Resolver::Resolver &resolver) + : mappings (mappings), resolver (resolver) +{} + +void +VisibilityResolver::go (HIR::Crate &crate) +{ + mappings.insert_visibility (crate.get_mappings ().get_nodeid (), + ModuleVisibility::create_public ()); + + current_module = crate.get_mappings ().get_defid (); + + for (auto &item : crate.items) + { + if (item->get_hir_kind () == HIR::Node::VIS_ITEM) + { + auto vis_item = static_cast (item.get ()); + vis_item->accept_vis (*this); + } + } +} + +bool +VisibilityResolver::resolve_module_path (const HIR::SimplePath &restriction, + DefId &id) +{ + // We need, from the restriction, to figure out the actual Module it + // belongs to. + + NodeId ast_node_id = restriction.get_mappings ().get_nodeid (); + + auto invalid_path + = Error (restriction.get_locus (), + "cannot use non-module path as privacy restrictor"); + + NodeId ref_node_id = UNKNOWN_NODEID; + if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id)) + { + invalid_path.emit_error (); + return false; + } + // FIXME: Add a hint here if we can find the path in another scope, such as + // a type or something else + // TODO: For the hint, can we point to the original item's definition if + // present? + + HirId ref; + rust_assert (mappings.lookup_node_to_hir (ref_node_id, &ref)); + + auto module = mappings.lookup_module (ref); + if (!module) + { + invalid_path.emit_error (); + return false; + } + + // Fill in the resolved `DefId` + id = module->get_mappings ().get_defid (); + + return true; +} + +bool +VisibilityResolver::resolve_visibility (const HIR::Visibility &visibility, + ModuleVisibility &to_resolve) +{ + switch (visibility.get_vis_type ()) + { + case HIR::Visibility::PRIVATE: + to_resolve = ModuleVisibility::create_restricted (current_module); + return true; + case HIR::Visibility::PUBLIC: + to_resolve = ModuleVisibility::create_public (); + return true; + case HIR::Visibility::RESTRICTED: { + // FIXME: We also need to handle 2015 vs 2018 edition conflicts + auto id = UNKNOWN_DEFID; + auto result = resolve_module_path (visibility.get_path (), id); + to_resolve = ModuleVisibility::create_restricted (id); + return result; + } + default: + gcc_unreachable (); + return false; + } +} + +void +VisibilityResolver::resolve_and_update (const HIR::VisItem *item) +{ + ModuleVisibility module_vis; + if (!resolve_visibility (item->get_visibility (), module_vis)) + return; // we will already have emitted errors + + mappings.insert_visibility (item->get_mappings ().get_nodeid (), module_vis); +} + +void +VisibilityResolver::visit (HIR::Module &mod) +{ + auto old_module = current_module; + current_module = mod.get_mappings ().get_defid (); + + for (auto &item : mod.get_items ()) + { + if (item->get_hir_kind () == HIR::Node::VIS_ITEM) + { + auto vis_item = static_cast (item.get ()); + vis_item->accept_vis (*this); + } + } + + current_module = old_module; +} + +void +VisibilityResolver::visit (HIR::ExternCrate &crate) +{} + +void +VisibilityResolver::visit (HIR::UseDeclaration &use_decl) +{} + +void +VisibilityResolver::visit (HIR::Function &func) +{ + resolve_and_update (&func); +} + +void +VisibilityResolver::visit (HIR::TypeAlias &type_alias) +{ + resolve_and_update (&type_alias); +} + +void +VisibilityResolver::visit (HIR::StructStruct &struct_item) +{ + resolve_and_update (&struct_item); +} + +void +VisibilityResolver::visit (HIR::TupleStruct &tuple_struct) +{ + resolve_and_update (&tuple_struct); +} + +void +VisibilityResolver::visit (HIR::Enum &enum_item) +{ + ModuleVisibility vis; + if (!resolve_visibility (enum_item.get_visibility (), vis)) + return; + + mappings.insert_visibility (enum_item.get_mappings ().get_nodeid (), vis); + for (auto &variant : enum_item.get_variants ()) + mappings.insert_visibility (variant->get_mappings ().get_nodeid (), vis); +} + +void +VisibilityResolver::visit (HIR::Union &union_item) +{} + +void +VisibilityResolver::visit (HIR::ConstantItem &const_item) +{ + resolve_and_update (&const_item); +} + +void +VisibilityResolver::visit (HIR::StaticItem &static_item) +{ + resolve_and_update (&static_item); +} + +void +VisibilityResolver::visit (HIR::Trait &trait) +{ + ModuleVisibility vis; + if (!resolve_visibility (trait.get_visibility (), vis)) + return; + + mappings.insert_visibility (trait.get_mappings ().get_nodeid (), vis); + for (auto &item : trait.get_trait_items ()) + mappings.insert_visibility (item->get_mappings ().get_nodeid (), vis); +} + +void +VisibilityResolver::visit (HIR::ImplBlock &impl) +{ + for (auto &item : impl.get_impl_items ()) + { + HIR::VisItem *vis_item; + switch (item->get_impl_item_type ()) + { + case HIR::ImplItem::FUNCTION: + vis_item = static_cast (item.get ()); + break; + case HIR::ImplItem::TYPE_ALIAS: + vis_item = static_cast (item.get ()); + break; + case HIR::ImplItem::CONSTANT: + vis_item = static_cast (item.get ()); + break; + default: + gcc_unreachable (); + return; + } + vis_item->accept_vis (*this); + } +} + +void +VisibilityResolver::visit (HIR::ExternBlock &block) +{} + +} // namespace Privacy +} // namespace Rust diff --git a/gcc/rust/checks/errors/privacy/rust-visibility-resolver.h b/gcc/rust/checks/errors/privacy/rust-visibility-resolver.h new file mode 100644 index 00000000000..20a581c16d4 --- /dev/null +++ b/gcc/rust/checks/errors/privacy/rust-visibility-resolver.h @@ -0,0 +1,103 @@ +// 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_VISIBILITY_H +#define RUST_VISIBILITY_H + +#include "rust-hir.h" +#include "rust-hir-expr.h" +#include "rust-hir-stmt.h" +#include "rust-hir-item.h" +#include "rust-hir-map.h" +#include "rust-name-resolver.h" +#include "rust-hir-visitor.h" + +namespace Rust { +namespace Privacy { + +class VisibilityResolver : public HIR::HIRVisItemVisitor +{ +public: + VisibilityResolver (Analysis::Mappings &mappings, + Rust::Resolver::Resolver &resolver); + + /** + * Perform visibility resolving on an entire crate + */ + void go (HIR::Crate &crate); + + /** + * Resolve a path to the module it refers + */ + bool resolve_module_path (const HIR::SimplePath &restriction, + DefId &to_resolve); + + /** + * Resolve the visibility of an item to its ModuleVisibility. This function + * emits errors if necessary. The contents of the to_resolve parameter will be + * overwritten on success. + * + * @param visibility Visibility of the item to resolve + * @param to_resolve ModuleVisibility reference to fill on success. + * + * @return false on error, true if the resolving was successful. + */ + bool resolve_visibility (const HIR::Visibility &visibility, + ModuleVisibility &to_resolve); + + /** + * Resolve the visibility of an item and updates it. This is useful for + * vis-items who need to be resolved but do not care about their module + * visibility - const items, static items, etc. For items with an impact on + * their children (enums, traits), this cannot be used + */ + void resolve_and_update (const HIR::VisItem *item); + + /** + * Get the DefId of the parent module we are currently visiting. + * + * @return UNKNOWN_DEFID if the module stack is empty, a valid `DefId` + * otherwise + */ + DefId peek_module (); + + virtual void visit (HIR::Module &mod); + virtual void visit (HIR::ExternCrate &crate); + virtual void visit (HIR::UseDeclaration &use_decl); + virtual void visit (HIR::Function &func); + virtual void visit (HIR::TypeAlias &type_alias); + virtual void visit (HIR::StructStruct &struct_item); + virtual void visit (HIR::TupleStruct &tuple_struct); + virtual void visit (HIR::Enum &enum_item); + virtual void visit (HIR::Union &union_item); + virtual void visit (HIR::ConstantItem &const_item); + virtual void visit (HIR::StaticItem &static_item); + virtual void visit (HIR::Trait &trait); + virtual void visit (HIR::ImplBlock &impl); + virtual void visit (HIR::ExternBlock &block); + +private: + Analysis::Mappings &mappings; + Rust::Resolver::Resolver &resolver; + DefId current_module; +}; + +} // namespace Privacy +} // namespace Rust + +#endif // !RUST_VISIBILITY_H From patchwork Wed Aug 24 11:59:45 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 57000 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 563BE382EA22 for ; Wed, 24 Aug 2022 12:06:41 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by sourceware.org (Postfix) with ESMTPS id AABE13891C0A; Wed, 24 Aug 2022 12:01:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org AABE13891C0A Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wm1-x32d.google.com with SMTP id l33-20020a05600c1d2100b003a645240a95so713265wms.1; Wed, 24 Aug 2022 05:01:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=bRZUDuEpx05IuKzN/4c8AJSmOy7JNJTRJcYx5LQI3ac=; b=T48zQnuCNvWfwHOZbplbShx3M6EK0+ZTF0WJGeW7IYa4qGa7ocuiuXCnrJXdxMmai6 bUOB3aij87qLCUpeA6WCJScx/9nx/QBkb/yLEWQ2A+omSbn+pf2uCNxSL08/6CheVHd/ lonRQCyvnRz0H3cl2HUTLnjh4/P7dEVxxWSHu1Pd0HQMWtxYVTOz3BHoHNJAJuA1A4HC nZkrAgWNO7/TMFEUf604AnMB9qdo+TIpB2tZslYRECp5b9l6S8qlILNzmvpJigBPg5hU DOGETXT51jRquuSC0ObiVyzY1IOxs2HnEs4J9+o330EKt46e7M9/fvv6ZwW3W/jDvLx7 YRgg== 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; bh=bRZUDuEpx05IuKzN/4c8AJSmOy7JNJTRJcYx5LQI3ac=; b=OBSQL2u4cSfTPKK4nFASPYEYw22PIUjDzckyIxvdLZj2laMWp9etuUp4JdcCEa519P eIrCeeo5ruh4eZ9cbAx9JAgmgm3yZ1cyZDZgZF56l6SqCjine+7CDRrRmClCwzUU5rAG gwx646jotRWowvPa2YKoNf0N8HNoX8YwW8kMI2H5R+NvQKWTsNsUjkZAMenrI1y0GAcX QqSNYgwJPXvsyY3F1zQMeDHHE9Amyg3bmu/VvM98qbE9xi7VpV/ov124PwNIPemetdLH NnIKcEeIqbSZR7pOGODpJ2dyP1zVW6kZ8dFLknXQ3L6NnEFNuKy1uEW6Hp1H1BB4lafp 8m8A== X-Gm-Message-State: ACgBeo3zBNlwrylo52a+XMUR5/PDB4UvhIfXN6ojC8vY7WHeKsJwiUjt T7a0F0VxCgNiFevKPpccsgn1gJcMsdo= X-Google-Smtp-Source: AA6agR75+UNXLwZKEl/wOzXcIUjGwqATdkWEuoPpw8+n62Rfmc8ktLg/okLmDke0QukIkBq/Uc4R4Q== X-Received: by 2002:a05:600c:410d:b0:3a6:1db8:b419 with SMTP id j13-20020a05600c410d00b003a61db8b419mr5021676wmi.119.1661342468013; Wed, 24 Aug 2022 05:01:08 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.01.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:01:07 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 26/37] gccrs: Add dead code scan on HIR Date: Wed, 24 Aug 2022 12:59:45 +0100 Message-Id: <20220824115956.737931-27-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-8.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_BENEFICIARYLOW, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Thomas Young Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Thomas Young In order to find dead code we use a depth first search and keep liveness variables, after type resolution. In this case, if a function is unused and it calls another function the 2nd function is now unused since the caller is not used etc. The algorithm is a depth first search. --- .../checks/lints/rust-lint-marklive-base.h | 45 +++ gcc/rust/checks/lints/rust-lint-marklive.cc | 282 ++++++++++++++++ gcc/rust/checks/lints/rust-lint-marklive.h | 308 ++++++++++++++++++ .../checks/lints/rust-lint-scan-deadcode.h | 154 +++++++++ 4 files changed, 789 insertions(+) create mode 100644 gcc/rust/checks/lints/rust-lint-marklive-base.h create mode 100644 gcc/rust/checks/lints/rust-lint-marklive.cc create mode 100644 gcc/rust/checks/lints/rust-lint-marklive.h create mode 100644 gcc/rust/checks/lints/rust-lint-scan-deadcode.h diff --git a/gcc/rust/checks/lints/rust-lint-marklive-base.h b/gcc/rust/checks/lints/rust-lint-marklive-base.h new file mode 100644 index 00000000000..97c068188b1 --- /dev/null +++ b/gcc/rust/checks/lints/rust-lint-marklive-base.h @@ -0,0 +1,45 @@ +// Copyright (C) 2021-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_HIR_LIVENESS_BASE +#define RUST_HIR_LIVENESS_BASE + +#include "rust-diagnostics.h" +#include "rust-lint-marklive.h" +#include "rust-lint-marklive-base.h" +#include "rust-hir-visitor.h" +#include "rust-hir-map.h" + +namespace Rust { +namespace Analysis { + +class MarkLiveBase : public HIR::HIRFullVisitorBase +{ +public: + virtual ~MarkLiveBase () {} + +protected: + MarkLiveBase () : mappings (Analysis::Mappings::get ()) {} + + Analysis::Mappings *mappings; +}; + +} // namespace Analysis +} // namespace Rust + +#endif diff --git a/gcc/rust/checks/lints/rust-lint-marklive.cc b/gcc/rust/checks/lints/rust-lint-marklive.cc new file mode 100644 index 00000000000..245632b4b4c --- /dev/null +++ b/gcc/rust/checks/lints/rust-lint-marklive.cc @@ -0,0 +1,282 @@ +// Copyright (C) 2021-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 +// . + +// The idea is that all reachable symbols are live, codes called +// from live codes are live, and everything else is dead. + +#include "rust-lint-marklive.h" +#include "rust-hir-full.h" +#include "rust-name-resolver.h" + +namespace Rust { +namespace Analysis { + +// This class trys to find the live symbols which can be used as +// seeds in MarkLive +// +// 1. TODO: explicit live +// - Attribute like #[allow(dead_code)] +// - Attribute like #[lang=".."], it's not a intra-crate item. +// 2. TODO: foreign item +class FindEntryPoint : public MarkLiveBase +{ + using Rust::Analysis::MarkLiveBase::visit; + +public: + static std::vector find (HIR::Crate &crate) + { + FindEntryPoint findEntryPoint; + for (auto it = crate.items.begin (); it != crate.items.end (); it++) + { + it->get ()->accept_vis (findEntryPoint); + } + return findEntryPoint.getEntryPoint (); + } + + // TODO not only fn main can be a entry point. + void visit (HIR::Function &function) override + { + if (function.get_function_name () == "main") + { + entryPoints.push_back (function.get_mappings ().get_hirid ()); + } + } + +private: + FindEntryPoint () : MarkLiveBase () {} + std::vector entryPoints; + std::vector getEntryPoint () { return entryPoints; } +}; + +std::set +MarkLive::Analysis (HIR::Crate &crate) +{ + MarkLive marklive (FindEntryPoint::find (crate)); + marklive.go (crate); + + return marklive.liveSymbols; +} + +// pop a live symbol from worklist every iteration, +// if it's a function then walk the function body, and +// 1. save all the live symbols in worklist which is +// visited first time +// 2. save all the live symbols in liveSymbols +void +MarkLive::go (HIR::Crate &crate) +{ + while (!worklist.empty ()) + { + HirId hirId = worklist.back (); + worklist.pop_back (); + scannedSymbols.emplace (hirId); + HIR::Item *item = mappings->lookup_hir_item (hirId); + liveSymbols.emplace (hirId); + if (item != nullptr) + { + item->accept_vis (*this); + } + else + { // the item maybe inside a trait impl + HirId parent_impl_id = UNKNOWN_HIRID; + HIR::ImplItem *implItem + = mappings->lookup_hir_implitem (hirId, &parent_impl_id); + if (implItem != nullptr) + implItem->accept_vis (*this); + } + } +} + +void +MarkLive::visit (HIR::PathInExpression &expr) +{ + // We should iterate every path segment in order to mark the struct which + // is used in expression like Foo::bar(), we should mark the Foo alive. + expr.iterate_path_segments ([&] (HIR::PathExprSegment &seg) -> bool { + return visit_path_segment (seg); + }); + + // after iterate the path segments, we should mark functions and associated + // functions alive. + NodeId ast_node_id = expr.get_mappings ().get_nodeid (); + NodeId ref_node_id = UNKNOWN_NODEID; + find_ref_node_id (ast_node_id, ref_node_id); + + // node back to HIR + HirId ref; + bool ok = mappings->lookup_node_to_hir (ref_node_id, &ref); + rust_assert (ok); + + // it must resolve to some kind of HIR::Item or HIR::InheritImplItem + HIR::Item *resolved_item = mappings->lookup_hir_item (ref); + if (resolved_item != nullptr) + { + mark_hir_id (resolved_item->get_mappings ().get_hirid ()); + } + else + { + HirId parent_impl_id = UNKNOWN_HIRID; + HIR::ImplItem *resolved_item + = mappings->lookup_hir_implitem (ref, &parent_impl_id); + if (resolved_item != nullptr) + { + mark_hir_id (resolved_item->get_impl_mappings ().get_hirid ()); + } + } +} + +void +MarkLive::visit (HIR::MethodCallExpr &expr) +{ + expr.get_receiver ()->accept_vis (*this); + visit_path_segment (expr.get_method_name ()); + for (auto &argument : expr.get_arguments ()) + argument->accept_vis (*this); + + // Trying to find the method definition and mark it alive. + NodeId ast_node_id = expr.get_mappings ().get_nodeid (); + NodeId ref_node_id = UNKNOWN_NODEID; + find_ref_node_id (ast_node_id, ref_node_id); + + // node back to HIR + HirId ref; + bool ok = mappings->lookup_node_to_hir (ref_node_id, &ref); + rust_assert (ok); + mark_hir_id (ref); +} + +bool +MarkLive::visit_path_segment (HIR::PathExprSegment seg) +{ + NodeId ast_node_id = seg.get_mappings ().get_nodeid (); + NodeId ref_node_id = UNKNOWN_NODEID; + + // There are two different kinds of segment for us. + // 1. function segment + // like the symbol "foo" in expression `foo()`. + // 2. type segment + // like the symbol "Foo" in expression `Foo{a: 1, b: 2}` + // + // We should mark them alive all and ignoring other kind of segments. + // If the segment we dont care then just return false is fine + if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) + { + if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id)) + return false; + } + HirId ref; + bool ok = mappings->lookup_node_to_hir (ref_node_id, &ref); + rust_assert (ok); + mark_hir_id (ref); + return true; +} + +void +MarkLive::visit (HIR::FieldAccessExpr &expr) +{ + // visit receiver at first + expr.get_receiver_expr ()->accept_vis (*this); + + // resolve the receiver back to ADT type + TyTy::BaseType *receiver = nullptr; + if (!tyctx->lookup_type ( + expr.get_receiver_expr ()->get_mappings ().get_hirid (), &receiver)) + { + rust_error_at (expr.get_receiver_expr ()->get_locus (), + "unresolved type for receiver"); + } + + TyTy::ADTType *adt = nullptr; + if (receiver->get_kind () == TyTy::TypeKind::ADT) + { + adt = static_cast (receiver); + } + else if (receiver->get_kind () == TyTy::TypeKind::REF) + { + TyTy::ReferenceType *r = static_cast (receiver); + TyTy::BaseType *b = r->get_base (); + rust_assert (b->get_kind () == TyTy::TypeKind::ADT); + + adt = static_cast (b); + } + + rust_assert (adt != nullptr); + rust_assert (!adt->is_enum ()); + rust_assert (adt->number_of_variants () == 1); + + TyTy::VariantDef *variant = adt->get_variants ().at (0); + + // get the field index + size_t index; + TyTy::StructFieldType *field; + bool ok = variant->lookup_field (expr.get_field_name (), &field, &index); + rust_assert (ok); + if (index >= variant->num_fields ()) + { + rust_error_at (expr.get_receiver_expr ()->get_locus (), + "cannot access struct %s by index: %lu", + adt->get_name ().c_str (), (unsigned long) index); + return; + } + + // get the field hir id + HirId field_id = field->get_ref (); + mark_hir_id (field_id); +} + +void +MarkLive::visit (HIR::TupleIndexExpr &expr) +{ + // TODO: unused tuple field detection + expr.get_tuple_expr ()->accept_vis (*this); +} + +void +MarkLive::visit (HIR::TypeAlias &alias) +{ + NodeId ast_node_id; + resolver->lookup_resolved_type ( + alias.get_type_aliased ()->get_mappings ().get_nodeid (), &ast_node_id); + HirId hir_id; + bool ok = mappings->lookup_node_to_hir (ast_node_id, &hir_id); + rust_assert (ok); + mark_hir_id (hir_id); +} + +void +MarkLive::mark_hir_id (HirId id) +{ + if (scannedSymbols.find (id) == scannedSymbols.end ()) + { + worklist.push_back (id); + } + liveSymbols.emplace (id); +} + +void +MarkLive::find_ref_node_id (NodeId ast_node_id, NodeId &ref_node_id) +{ + if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id)) + { + bool ok = resolver->lookup_resolved_type (ast_node_id, &ref_node_id); + rust_assert (ok); + } +} + +} // namespace Analysis +} // namespace Rust diff --git a/gcc/rust/checks/lints/rust-lint-marklive.h b/gcc/rust/checks/lints/rust-lint-marklive.h new file mode 100644 index 00000000000..119af8b8c95 --- /dev/null +++ b/gcc/rust/checks/lints/rust-lint-marklive.h @@ -0,0 +1,308 @@ +// Copyright (C) 2021-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_HIR_LIVENESS +#define RUST_HIR_LIVENESS + +#include "rust-hir-full-decls.h" +#include "rust-hir-map.h" +#include "rust-lint-marklive-base.h" +#include "rust-name-resolver.h" + +namespace Rust { +namespace Analysis { + +class MarkLive : public MarkLiveBase +{ + using Rust::Analysis::MarkLiveBase::visit; + +public: + static std::set Analysis (HIR::Crate &crate); + void go (HIR::Crate &crate); + + void visit (HIR::PathInExpression &expr) override; + void visit (HIR::FieldAccessExpr &expr) override; + void visit (HIR::TupleIndexExpr &expr) override; + void visit (HIR::MethodCallExpr &expr) override; + void visit (HIR::TypeAlias &alias) override; + + void visit (HIR::BorrowExpr &expr) override + { + expr.get_expr ()->accept_vis (*this); + } + + void visit (HIR::DereferenceExpr &expr) override + { + expr.get_expr ()->accept_vis (*this); + } + + void visit (HIR::NegationExpr &expr) override + { + expr.get_expr ()->accept_vis (*this); + } + + void visit (HIR::LazyBooleanExpr &expr) override + { + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); + } + + void visit (HIR::TypeCastExpr &expr) override + { + expr.get_expr ()->accept_vis (*this); + } + + void visit (HIR::GroupedExpr &expr) override + { + expr.get_expr_in_parens ()->accept_vis (*this); + } + + void visit (HIR::ArrayExpr &expr) override + { + expr.get_internal_elements ()->accept_vis (*this); + } + + void visit (HIR::ArrayIndexExpr &expr) override + { + expr.get_array_expr ()->accept_vis (*this); + expr.get_index_expr ()->accept_vis (*this); + } + + void visit (HIR::ArrayElemsValues &expr) override + { + for (auto &elem : expr.get_values ()) + { + elem->accept_vis (*this); + } + } + + void visit (HIR::TupleExpr &expr) override + { + for (auto &elem : expr.get_tuple_elems ()) + { + elem->accept_vis (*this); + } + } + + void visit (HIR::BlockExpr &expr) override + { + for (auto &s : expr.get_statements ()) + { + s->accept_vis (*this); + } + if (expr.has_expr ()) + { + expr.get_final_expr ()->accept_vis (*this); + } + } + + void visit (HIR::UnsafeBlockExpr &expr) override + { + expr.get_block_expr ()->accept_vis (*this); + } + + void visit (HIR::LoopExpr &expr) override + { + expr.get_loop_block ()->accept_vis (*this); + } + + void visit (HIR::BreakExpr &expr) override + { + if (expr.has_break_expr ()) + expr.get_expr ()->accept_vis (*this); + } + + void visit (HIR::WhileLoopExpr &expr) override + { + expr.get_loop_block ()->accept_vis (*this); + expr.get_predicate_expr ()->accept_vis (*this); + } + + void visit (HIR::Function &function) override + { + function.get_definition ()->accept_vis (*this); + } + + void visit (HIR::ReturnExpr &expr) override + { + if (expr.has_return_expr ()) + expr.get_expr ()->accept_vis (*this); + } + + void visit (HIR::WhileLetLoopExpr &expr) override + { + expr.get_loop_block ()->accept_vis (*this); + expr.get_cond ()->accept_vis (*this); + } + + void visit (HIR::ForLoopExpr &expr) override + { + expr.get_loop_block ()->accept_vis (*this); + expr.get_iterator_expr ()->accept_vis (*this); + } + + void visit (HIR::ExprStmtWithoutBlock &stmt) override + { + stmt.get_expr ()->accept_vis (*this); + } + + void visit (HIR::ExprStmtWithBlock &stmt) override + { + stmt.get_expr ()->accept_vis (*this); + } + + void visit (HIR::CallExpr &expr) override + { + expr.get_fnexpr ()->accept_vis (*this); + for (auto &argument : expr.get_arguments ()) + argument->accept_vis (*this); + } + + void visit (HIR::ArithmeticOrLogicalExpr &expr) override + { + expr.visit_lhs (*this); + expr.visit_rhs (*this); + } + void visit (HIR::ComparisonExpr &expr) override + { + expr.get_lhs ()->accept_vis (*this); + expr.get_rhs ()->accept_vis (*this); + } + + void visit (HIR::AssignmentExpr &expr) override + { + expr.visit_lhs (*this); + expr.visit_rhs (*this); + } + + void visit (HIR::CompoundAssignmentExpr &expr) override + { + expr.visit_lhs (*this); + expr.visit_rhs (*this); + } + + void visit (HIR::IfExpr &expr) override + { + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + } + + void visit (HIR::IfExprConseqElse &expr) override + { + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + expr.get_else_block ()->accept_vis (*this); + } + + void visit (HIR::MatchExpr &expr) override + { + expr.get_scrutinee_expr ()->accept_vis (*this); + std::vector &cases = expr.get_match_cases (); + for (auto &&caz : cases) + { + auto case_arm = caz.get_arm (); + if (case_arm.has_match_arm_guard ()) + case_arm.get_guard_expr ()->accept_vis (*this); + caz.get_expr ()->accept_vis (*this); + } + } + + void visit (HIR::IfExprConseqIf &expr) override + { + expr.get_if_condition ()->accept_vis (*this); + expr.get_if_block ()->accept_vis (*this); + expr.get_conseq_if_expr ()->accept_vis (*this); + } + + void visit (HIR::TraitItemFunc &item) override + { + item.get_block_expr ()->accept_vis (*this); + } + + void visit (HIR::ImplBlock &impl) override + { + for (auto &&item : impl.get_impl_items ()) + { + item->accept_vis (*this); + } + } + + void visit (HIR::LetStmt &stmt) override + { + if (stmt.has_init_expr ()) + { + stmt.get_init_expr ()->accept_vis (*this); + } + } + + void visit (HIR::StructExprStruct &stct) override + { + stct.get_struct_name ().accept_vis (*this); + } + + void visit (HIR::StructExprStructFields &stct) override + { + for (auto &field : stct.get_fields ()) + { + field->accept_vis (*this); + } + + stct.get_struct_name ().accept_vis (*this); + if (stct.has_struct_base ()) + { + stct.struct_base->base_struct->accept_vis (*this); + } + } + + virtual void visit (HIR::StructExprFieldIdentifierValue &field) override + { + field.get_value ()->accept_vis (*this); + } + + void visit (HIR::StructExprStructBase &stct) override + { + stct.get_struct_base ()->base_struct->accept_vis (*this); + } + + void visit (HIR::Module &module) override + { + for (auto &item : module.get_items ()) + item->accept_vis (*this); + } + +private: + std::vector worklist; + std::set liveSymbols; + std::set scannedSymbols; + Analysis::Mappings *mappings; + Resolver::Resolver *resolver; + Resolver::TypeCheckContext *tyctx; + MarkLive (std::vector worklist) + : worklist (worklist), mappings (Analysis::Mappings::get ()), + resolver (Resolver::Resolver::get ()), + tyctx (Resolver::TypeCheckContext::get ()){}; + + void mark_hir_id (HirId); + bool visit_path_segment (HIR::PathExprSegment); + void find_ref_node_id (NodeId ast_node_id, NodeId &ref_node_id); +}; + +} // namespace Analysis +} // namespace Rust + +#endif diff --git a/gcc/rust/checks/lints/rust-lint-scan-deadcode.h b/gcc/rust/checks/lints/rust-lint-scan-deadcode.h new file mode 100644 index 00000000000..591cb30bc24 --- /dev/null +++ b/gcc/rust/checks/lints/rust-lint-scan-deadcode.h @@ -0,0 +1,154 @@ +// Copyright (C) 2021-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_HIR_SCAN_DEADCODE +#define RUST_HIR_SCAN_DEADCODE + +#include "rust-hir-full-decls.h" +#include "rust-hir-map.h" +#include "rust-lint-marklive.h" +#include "rust-name-resolver.h" +#include "rust-diagnostics.h" + +namespace Rust { +namespace Analysis { + +// Scan item symbols and warn the symbol if it is not in the live_symbols set. +// There are three kinds of item we should handle in this pass. +// 1. Function item +// 2. The function item in the impl block without trait +// 3. StructStruct, e.g., `Struct Foo{one: 1, two: 2}`. Furthermore, the unused +// struct fields will be warned too. +// 4. TupleStruct, e.g., `Struct Foo(i32, i32)` +class ScanDeadcode : public MarkLiveBase +{ + using Rust::Analysis::MarkLiveBase::visit; + +public: + static void Scan (HIR::Crate &crate) + { + std::set live_symbols = Analysis::MarkLive::Analysis (crate); + ScanDeadcode sdc (live_symbols); + for (auto it = crate.items.begin (); it != crate.items.end (); it++) + { + it->get ()->accept_vis (sdc); + } + }; + + void visit (HIR::Function &function) override + { + HirId hirId = function.get_mappings ().get_hirid (); + if (should_warn (hirId)) + { + if (mappings->is_impl_item (hirId)) + { + HIR::ImplBlock *implBlock + = mappings->lookup_associated_impl (hirId); + if (!implBlock->has_trait_ref ()) + { + rust_warning_at (function.get_locus (), 0, + "associated function is never used: %<%s%>", + function.get_function_name ().c_str ()); + } + } + else + { + rust_warning_at (function.get_locus (), 0, + "function is never used: %<%s%>", + function.get_function_name ().c_str ()); + } + } + } + + void visit (HIR::StructStruct &stct) override + { + HirId hirId = stct.get_mappings ().get_hirid (); + if (should_warn (hirId)) + { + bool name_starts_underscore = stct.get_identifier ().at (0) == '_'; + if (!name_starts_underscore) + rust_warning_at (stct.get_locus (), 0, + "struct is never constructed: %<%s%>", + stct.get_identifier ().c_str ()); + } + else + { + // only warn the unused fields when in unwarned struct. + for (auto &field : stct.get_fields ()) + { + HirId field_hir_id = field.get_mappings ().get_hirid (); + if (should_warn (field_hir_id)) + { + rust_warning_at (field.get_locus (), 0, + "field is never read: %<%s%>", + field.get_field_name ().c_str ()); + } + } + } + } + + void visit (HIR::TupleStruct &stct) override + { + // only warn tuple struct unconstructed, and ignoring unused field + HirId hirId = stct.get_mappings ().get_hirid (); + if (should_warn (hirId)) + { + rust_warning_at (stct.get_locus (), 0, + "struct is never constructed: %<%s%>", + stct.get_identifier ().c_str ()); + } + } + + void visit (HIR::ImplBlock &blc) override + { + if (blc.has_impl_items ()) + { + for (auto &implItem : blc.get_impl_items ()) + { + implItem->accept_vis (*this); + } + } + } + + void visit (HIR::Module &mod) override + { + for (auto &item : mod.get_items ()) + item->accept_vis (*this); + } + +private: + std::set live_symbols; + Resolver::Resolver *resolver; + Analysis::Mappings *mappings; + + ScanDeadcode (std::set &live_symbols) + : live_symbols (live_symbols), resolver (Resolver::Resolver::get ()), + mappings (Analysis::Mappings::get ()){}; + + bool should_warn (HirId hirId) + { + // TODO: There are more condition to check if should warn, i.e visibility, + // attributes. + return live_symbols.find (hirId) == live_symbols.end (); + } +}; + +} // namespace Analysis +} // namespace Rust + +#endif From patchwork Wed Aug 24 11:59:46 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56999 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 40C84382EA0C for ; Wed, 24 Aug 2022 12:06:40 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x429.google.com (mail-wr1-x429.google.com [IPv6:2a00:1450:4864:20::429]) by sourceware.org (Postfix) with ESMTPS id F008438A90BB; Wed, 24 Aug 2022 12:01:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org F008438A90BB Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x429.google.com with SMTP id b5so16204991wrr.5; Wed, 24 Aug 2022 05:01:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=2+xQFlaMBp9eqjhcZ8kafuZJmQUKrkM4HDGSADjdv04=; b=GZNqsoOgQfNE4rBgpsa3+uo3sOGAKonslZh0l3f085wFsg07FLowUeH++23afzfmZu AiFrprlswp3pX2ppTI9UERXaSCZKUth5/isqji5tUsm3/Os0+rJG+jG5sWjKjsQUvyR8 e5Q27guQsOzfZXkZl1xTwYR6nVlbSOy9/41mja9dP3X6oRtxVTic83zCjTZD4YncUTBS 1Q9achwiSg9422SjCKv7L1RcW7CVo5vNvBC1qIm0hIa09ereLOii5oU43U8r6liHgaAe PZ4np0z0G9JF5uKPLwpwXxJrtquZuDXQroBvjLVZk/QkJNoIxmIo9MGlUmRpwMdfo+Xv eSew== 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; bh=2+xQFlaMBp9eqjhcZ8kafuZJmQUKrkM4HDGSADjdv04=; b=lQSgUMy0M/LKuOdwI0YTYuYMXK84+sbtIBA9iKWX6N2DC46epWVAeqPc+AwySyN73Y ssr+9jq464H7o+Sd3gsRIwMjAnApBvvWTv1OaGmJJRFjYOvdRCICPkSBa0fQohrqu/Yu M5fQgspvpUKwx11XYlx9+xOnnQ9FlHyrJduGus/SEi+84Dr3FAVY6ejAp7raXYzOu7yU tJitw91I0afGlaa4AXRdkZm+tOSWFcVAtj/H20evFB/dChykVcPXqr79UQDPFOoToyNP XWYDiBrYaGcR/BscCpu257ZtPNz2y0kymcf2hP0SedFr8/1jXKEoR1iI52dpd03qfgmk E/sg== X-Gm-Message-State: ACgBeo1PhP88AZB5zWxcE2cOBFlVNc2evVhcbEJ/vCd5vZbM1VdeUw1m UWs64BsqmZv97yobfXiSh6uOSjROSIk= X-Google-Smtp-Source: AA6agR78ZWsdlA0w/wYJiZ7veJLbcMN8CAMQ2eFCW/l3DqXQksRx/i3gIi89rfeyZHi9k1cJuY2cCA== X-Received: by 2002:a05:6000:168f:b0:225:603a:cdb1 with SMTP id y15-20020a056000168f00b00225603acdb1mr6127923wrd.569.1661342469355; Wed, 24 Aug 2022 05:01:09 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.01.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:01:08 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 27/37] gccrs: Add unused variable scan Date: Wed, 24 Aug 2022 12:59:46 +0100 Message-Id: <20220824115956.737931-28-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron This is a simple walk_tree which acts on the monomorphized code. By walking the compiled translation unit of functions. --- gcc/rust/checks/lints/rust-lint-unused-var.cc | 98 +++++++++++++++++++ gcc/rust/checks/lints/rust-lint-unused-var.h | 36 +++++++ 2 files changed, 134 insertions(+) create mode 100644 gcc/rust/checks/lints/rust-lint-unused-var.cc create mode 100644 gcc/rust/checks/lints/rust-lint-unused-var.h diff --git a/gcc/rust/checks/lints/rust-lint-unused-var.cc b/gcc/rust/checks/lints/rust-lint-unused-var.cc new file mode 100644 index 00000000000..d4317e53280 --- /dev/null +++ b/gcc/rust/checks/lints/rust-lint-unused-var.cc @@ -0,0 +1,98 @@ +// Copyright (C) 2021-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-lint-unused-var.h" +#include "print-tree.h" + +namespace Rust { +namespace Analysis { + +static void +check_decl (tree *t) +{ + rust_assert (TREE_CODE (*t) == VAR_DECL || TREE_CODE (*t) == PARM_DECL + || TREE_CODE (*t) == CONST_DECL); + + tree var_name = DECL_NAME (*t); + const char *var_name_ptr = IDENTIFIER_POINTER (var_name); + bool starts_with_under_score = strncmp (var_name_ptr, "_", 1) == 0; + + bool is_constant = TREE_CODE (*t) == CONST_DECL; + // if (!is_constant) + // { + // debug_tree (*t); + // rust_debug ("found var-decl: used %s artifical %s underscore %s name + // %s", + // TREE_USED (*t) ? "true" : "false", + // DECL_ARTIFICIAL (*t) ? "true" : "false", + // starts_with_under_score ? "true" : "false", var_name_ptr); + // } + + if (!TREE_USED (*t) && !DECL_ARTIFICIAL (*t) && !starts_with_under_score) + { + warning_at (DECL_SOURCE_LOCATION (*t), + is_constant ? OPT_Wunused_const_variable_ + : OPT_Wunused_variable, + "unused name %qE", *t); + } +} + +static tree +unused_var_walk_fn (tree *t, int *walk_subtrees, void *closure) +{ + switch (TREE_CODE (*t)) + { + case VAR_DECL: + case CONST_DECL: + check_decl (t); + break; + + default: + break; + } + return NULL_TREE; +} + +void +UnusedVariables::Lint (Compile::Context &ctx) +{ + for (auto &fndecl : ctx.get_func_decls ()) + { + for (tree p = DECL_ARGUMENTS (fndecl); p != NULL_TREE; p = DECL_CHAIN (p)) + { + check_decl (&p); + } + + walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl), + &unused_var_walk_fn, &ctx); + } + + for (auto &var : ctx.get_var_decls ()) + { + tree t = ctx.get_backend ()->var_expression (var, Location ()); + check_decl (&t); + } + + for (auto &const_decl : ctx.get_const_decls ()) + { + check_decl (&const_decl); + } +} + +} // namespace Analysis +} // namespace Rust diff --git a/gcc/rust/checks/lints/rust-lint-unused-var.h b/gcc/rust/checks/lints/rust-lint-unused-var.h new file mode 100644 index 00000000000..6fabfeff01b --- /dev/null +++ b/gcc/rust/checks/lints/rust-lint-unused-var.h @@ -0,0 +1,36 @@ +// Copyright (C) 2021-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_LINT_UNUSED_VAR +#define RUST_LINT_UNUSED_VAR + +#include "rust-compile-context.h" + +namespace Rust { +namespace Analysis { + +class UnusedVariables +{ +public: + static void Lint (Compile::Context &ctx); +}; + +} // namespace Analysis +} // namespace Rust + +#endif // RUST_LINT_UNUSED_VAR From patchwork Wed Aug 24 11:59:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 57007 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 77B7E388D1C2 for ; Wed, 24 Aug 2022 12:08:42 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x333.google.com (mail-wm1-x333.google.com [IPv6:2a00:1450:4864:20::333]) by sourceware.org (Postfix) with ESMTPS id 5037F385141F; Wed, 24 Aug 2022 12:01:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 5037F385141F Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wm1-x333.google.com with SMTP id m10-20020a05600c3b0a00b003a603fc3f81so722314wms.0; Wed, 24 Aug 2022 05:01:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=KatFTpmnNhw3XaHAMPemoDUHBYLnumltBkiiVOPQ8f4=; b=peHJGAgaZ5+JGe9DLa75kKnCrtMpznKHrAetN9O2XieaVeQQnO7048G4WelFSOdHAN u4uD7y/8exJlbMlV8vn+C/P7/F10Z/90yGIrFq4hHioLLSIs0QQH0ZV1++KPSZkOgJ4u YRYYJ4OKHl+tvHRbZgNf9l/NkbpbTRjbJgNOnUqlhmueqKTHiITGRaGtA7QDdmW7OzAd +lT0wZDs5SZYi2100fJGLg5QZsATBR/mwODLRXm3fNjiD5ge1fWrqWXyExfOiMMVZLwo NFioxrFYyPPByKELPC9mzeaEg5v9C9nrnpL+FHdfAavuwoKHHwmzXKvw+aiQcdo18hen N6rw== 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; bh=KatFTpmnNhw3XaHAMPemoDUHBYLnumltBkiiVOPQ8f4=; b=MwA4ZkOqJD1MdcdYUwErxujoJxthKMyovbbvO/HDJGlt1Lh6pmI9LnmaNkT6VGw97G d29m05i0sbifRlOVqdgBcBlcNzzBCWIKpGn7ixYFfBkbzS8boSGnUqqQ+2Ad0TZrh7dt SZvHJKTVtl9zxBq8G+dysVWRNl7bBP+rACVqx/FRRs21Ri/LAGdQp66GoWU/FWP4fuPa 8zcvKP3rS7Y4FTJ5agopw0Y1UfVwaunZh7OvgYxuLjUk4grvpL+8rKdajXuC0qDxiK6B 0VW8dP26TfdQmQFeisav5sxENG45mTY3VclD8Qg54mJO/NRsSUrxhZyuhladZPEiCVLM HsEQ== X-Gm-Message-State: ACgBeo07KnTzirQ+evuReBFQ4RfrDPsXX24KY1bPlKfHboH4MA+q09dF b48Kv1kCLiB2ebhoeHzvGBLWfKuJkJA= X-Google-Smtp-Source: AA6agR7d9CBg4E9AIfkrOlh34htrO0uNDbY01fgn5S67Xl93pM9yB/mv0qTa2HAhDSg6HKWJ85WNvg== X-Received: by 2002:a1c:a107:0:b0:3a6:8b06:cf19 with SMTP id k7-20020a1ca107000000b003a68b06cf19mr1807747wme.195.1661342470730; Wed, 24 Aug 2022 05:01:10 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.01.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:01:09 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 28/37] gccrs: Add metadata ouptput pass Date: Wed, 24 Aug 2022 12:59:47 +0100 Message-Id: <20220824115956.737931-29-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron Extern crates statements to tell the front-end to look for another library. The mechanism here is heavily inspired from gccgo, so when we compile a library for example we invoke: gccrs -g -O2 -frust-crate=mylib -c src/lib.rs -o src/mylib.o All going well this object file will now contain extra data inside .rust-export section inside the object file which will be preserved inside archives and shared objects. When we have another application which uses this library 'mylib'. extern crate mylib; use mylib::foo; fn main() { foo(); } We compile using: gcc -g -O2 -frust-crate=test -c src/main.rs -o src/main.o When the extern crate line is hit the front-end will look for mylib.o, libmylib.a, mylib.rox. If it finds a raw object file it will read the .rust-export section directly from the object for the public metadata such as public functions, types constants etc. If it fails to find an object it might find .rox which is the objdump of the .rust-export to a raw file, it might even find libmylib.a and read the export directly out of the archive file reusing code from gccgo to do so. The full compiler pipeline is reused here, so the metatadata is actually just real rust code. The benifit here is that Rust supports exporting, macros and generics so this requires the name-resolution and type info all to be generated and inserted into the apropriate context classes. Since the metadata is real rust code it means we can reuse the full pipeline to generate the code as nessecary. So for the simple case of a public struct we simply emit the AST dump of this struct directly into the metadata. If its a non-generic public function we emit and extern rust abi block for that function. If its a trait we can simply emit the trait with the public memebers. Generics are more complicated since we need to emit the function fully for it to be compiled correctly this still needs tests to be added. The hardest part is non generic impl blocks which is still a WIP. To finally link the two crates together you run: gcc -g -O2 -o rust-program.exe src/main.o src/mylib.o --- gcc/rust/metadata/rust-export-metadata.cc | 385 ++++++++++ gcc/rust/metadata/rust-export-metadata.h | 85 +++ gcc/rust/metadata/rust-extern-crate.cc | 173 +++++ gcc/rust/metadata/rust-extern-crate.h | 55 ++ gcc/rust/metadata/rust-import-archive.cc | 885 ++++++++++++++++++++++ gcc/rust/metadata/rust-imports.cc | 441 +++++++++++ gcc/rust/metadata/rust-imports.h | 257 +++++++ gcc/rust/rust-object-export.cc | 177 +++++ gcc/rust/rust-object-export.h | 33 + 9 files changed, 2491 insertions(+) create mode 100644 gcc/rust/metadata/rust-export-metadata.cc create mode 100644 gcc/rust/metadata/rust-export-metadata.h create mode 100644 gcc/rust/metadata/rust-extern-crate.cc create mode 100644 gcc/rust/metadata/rust-extern-crate.h create mode 100644 gcc/rust/metadata/rust-import-archive.cc create mode 100644 gcc/rust/metadata/rust-imports.cc create mode 100644 gcc/rust/metadata/rust-imports.h create mode 100644 gcc/rust/rust-object-export.cc create mode 100644 gcc/rust/rust-object-export.h diff --git a/gcc/rust/metadata/rust-export-metadata.cc b/gcc/rust/metadata/rust-export-metadata.cc new file mode 100644 index 00000000000..4856bc26149 --- /dev/null +++ b/gcc/rust/metadata/rust-export-metadata.cc @@ -0,0 +1,385 @@ +// 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 +// . + +#include "rust-export-metadata.h" +#include "rust-hir-visitor.h" +#include "rust-hir-full.h" +#include "rust-hir-map.h" +#include "rust-ast-dump.h" +#include "rust-abi.h" +#include "rust-object-export.h" + +#include "md5.h" + +namespace Rust { +namespace Metadata { + +static const std::string extension_path = ".rox"; + +ExportContext::ExportContext () : mappings (Analysis::Mappings::get ()) {} + +ExportContext::~ExportContext () {} + +void +ExportContext::push_module_scope (const HIR::Module &module) +{ + module_stack.push_back (module); +} + +const HIR::Module & +ExportContext::pop_module_scope () +{ + rust_assert (!module_stack.empty ()); + const HIR::Module &poped = module_stack.back (); + module_stack.pop_back (); + return poped; +} + +void +ExportContext::emit_trait (const HIR::Trait &trait) +{ + // lookup the AST node for this + AST::Item *item = nullptr; + bool ok + = mappings->lookup_ast_item (trait.get_mappings ().get_nodeid (), &item); + rust_assert (ok); + + std::stringstream oss; + AST::Dump dumper (oss); + dumper.go (*item); + + public_interface_buffer += oss.str (); +} + +void +ExportContext::emit_function (const HIR::Function &fn) +{ + // lookup the AST node for this + AST::Item *item = nullptr; + bool ok = mappings->lookup_ast_item (fn.get_mappings ().get_nodeid (), &item); + rust_assert (ok); + + // is this a CFG macro or not + if (item->is_marked_for_strip ()) + return; + + // FIXME add assertion that item must be a vis_item; + AST::VisItem &vis_item = static_cast (*item); + + // if its a generic function we need to output the full declaration + // otherwise we can let people link against this + + std::stringstream oss; + AST::Dump dumper (oss); + if (!fn.has_generics ()) + { + // FIXME assert that this is actually an AST::Function + AST::Function &function = static_cast (vis_item); + + // we can emit an extern block with abi of "rust" + Identifier item_name = function.get_function_name (); + + // always empty for extern linkage + AST::WhereClause where_clause = AST::WhereClause::create_empty (); + std::vector> generic_params; + + AST::Visibility vis = function.get_visibility (); + std::unique_ptr return_type + = std::unique_ptr (nullptr); + if (function.has_return_type ()) + { + return_type = function.get_return_type ()->clone_type (); + } + + std::vector function_params; + for (AST::FunctionParam ¶m : function.get_function_params ()) + { + std::string name = param.get_pattern ()->as_string (); + std::unique_ptr param_type + = param.get_type ()->clone_type (); + + AST::NamedFunctionParam p (name, std::move (param_type), {}, + param.get_locus ()); + function_params.push_back (std::move (p)); + } + + AST::ExternalItem *external_item = new AST::ExternalFunctionItem ( + item_name, {} /* generic_params */, std::move (return_type), + where_clause, std::move (function_params), false /* has_variadics */, + {} /* variadic_outer_attrs */, vis, function.get_outer_attrs (), + function.get_locus ()); + + std::vector> external_items; + external_items.push_back ( + std::unique_ptr (external_item)); + + AST::ExternBlock extern_block (get_string_from_abi (Rust::ABI::RUST), + std::move (external_items), + vis_item.get_visibility (), {}, {}, + fn.get_locus ()); + + dumper.go (extern_block); + } + else + { + dumper.go (*item); + } + + // store the dump + public_interface_buffer += oss.str (); +} + +const std::string & +ExportContext::get_interface_buffer () const +{ + return public_interface_buffer; +} + +// implicitly by using HIR nodes we know that these have passed CFG expansion +// and they exist in the compilation unit +class ExportVisItems : public HIR::HIRVisItemVisitor +{ +public: + ExportVisItems (ExportContext &context) : ctx (context) {} + + void visit (HIR::Module &module) override {} + void visit (HIR::ExternCrate &crate) override {} + void visit (HIR::UseDeclaration &use_decl) override {} + void visit (HIR::TypeAlias &type_alias) override {} + void visit (HIR::StructStruct &struct_item) override {} + void visit (HIR::TupleStruct &tuple_struct) override {} + void visit (HIR::Enum &enum_item) override {} + void visit (HIR::Union &union_item) override {} + void visit (HIR::ConstantItem &const_item) override {} + void visit (HIR::StaticItem &static_item) override {} + void visit (HIR::ImplBlock &impl) override {} + void visit (HIR::ExternBlock &block) override {} + + void visit (HIR::Trait &trait) override { ctx.emit_trait (trait); } + + void visit (HIR::Function &function) override + { + ctx.emit_function (function); + } + +private: + ExportContext &ctx; +}; + +PublicInterface::PublicInterface (HIR::Crate &crate) + : crate (crate), mappings (*Analysis::Mappings::get ()), context () +{} + +void +PublicInterface::Export (HIR::Crate &crate) +{ + PublicInterface interface (crate); + interface.gather_export_data (); + interface.write_to_object_file (); +} + +void +PublicInterface::ExportTo (HIR::Crate &crate, const std::string &output_path) +{ + PublicInterface interface (crate); + interface.gather_export_data (); + interface.write_to_path (output_path); +} + +void +PublicInterface::gather_export_data () +{ + ExportVisItems visitor (context); + for (auto &item : crate.items) + { + bool is_vis_item = item->get_hir_kind () == HIR::Node::BaseKind::VIS_ITEM; + if (!is_vis_item) + continue; + + HIR::VisItem &vis_item = static_cast (*item.get ()); + if (is_crate_public (vis_item)) + vis_item.accept_vis (visitor); + } +} + +void +PublicInterface::write_to_object_file () const +{ + // done + const auto &buf = context.get_interface_buffer (); + std::string size_buffer = std::to_string (buf.size ()); + + // md5 this + struct md5_ctx chksm; + unsigned char checksum[16]; + + md5_init_ctx (&chksm); + md5_process_bytes (buf.c_str (), buf.size (), &chksm); + md5_finish_ctx (&chksm, checksum); + + // MAGIC MD5 DLIM DLIM buffer-size DELIM contents + const std::string current_crate_name = mappings.get_current_crate_name (); + + // extern void + rust_write_export_data (kMagicHeader, sizeof (kMagicHeader)); + rust_write_export_data ((const char *) checksum, sizeof (checksum)); + rust_write_export_data (kSzDelim, sizeof (kSzDelim)); + rust_write_export_data (current_crate_name.c_str (), + current_crate_name.size ()); + rust_write_export_data (kSzDelim, sizeof (kSzDelim)); + rust_write_export_data (size_buffer.c_str (), size_buffer.size ()); + rust_write_export_data (kSzDelim, sizeof (kSzDelim)); + rust_write_export_data (buf.c_str (), buf.size ()); +} + +void +PublicInterface::write_to_path (const std::string &path) const +{ + // validate path contains correct extension + const std::string expected_file_name = expected_metadata_filename (); + const char *path_base_name = basename (path.c_str ()); + if (strcmp (path_base_name, expected_file_name.c_str ()) != 0) + { + rust_error_at (Location (), + "expected metadata-output path to have base file name of: " + "%<%s%> got %<%s%>", + expected_file_name.c_str (), path_base_name); + return; + } + + // done + const auto &buf = context.get_interface_buffer (); + std::string size_buffer = std::to_string (buf.size ()); + + // md5 this + struct md5_ctx chksm; + unsigned char checksum[16]; + + md5_init_ctx (&chksm); + md5_process_bytes (buf.c_str (), buf.size (), &chksm); + md5_finish_ctx (&chksm, checksum); + + // MAGIC MD5 DLIM DLIM buffer-size DELIM contents + const std::string current_crate_name = mappings.get_current_crate_name (); + + // write to path + FILE *nfd = fopen (path.c_str (), "wb"); + if (nfd == NULL) + { + rust_error_at (Location (), "failed to open file %<%s%> for writing: %s", + path.c_str (), xstrerror (errno)); + return; + } + + // write data + if (fwrite (kMagicHeader, sizeof (kMagicHeader), 1, nfd) < 1) + { + rust_error_at (Location (), "failed to write to file %<%s%>: %s", + path.c_str (), xstrerror (errno)); + fclose (nfd); + return; + } + + if (fwrite (checksum, sizeof (checksum), 1, nfd) < 1) + { + rust_error_at (Location (), "failed to write to file %<%s%>: %s", + path.c_str (), xstrerror (errno)); + fclose (nfd); + return; + } + + if (fwrite (kSzDelim, sizeof (kSzDelim), 1, nfd) < 1) + { + rust_error_at (Location (), "failed to write to file %<%s%>: %s", + path.c_str (), xstrerror (errno)); + fclose (nfd); + return; + } + + if (fwrite (current_crate_name.c_str (), current_crate_name.size (), 1, nfd) + < 1) + { + rust_error_at (Location (), "failed to write to file %<%s%>: %s", + path.c_str (), xstrerror (errno)); + fclose (nfd); + return; + } + + if (fwrite (kSzDelim, sizeof (kSzDelim), 1, nfd) < 1) + { + rust_error_at (Location (), "failed to write to file %<%s%>: %s", + path.c_str (), xstrerror (errno)); + fclose (nfd); + return; + } + + if (fwrite (size_buffer.c_str (), size_buffer.size (), 1, nfd) < 1) + { + rust_error_at (Location (), "failed to write to file %<%s%>: %s", + path.c_str (), xstrerror (errno)); + fclose (nfd); + return; + } + + if (fwrite (kSzDelim, sizeof (kSzDelim), 1, nfd) < 1) + { + rust_error_at (Location (), "failed to write to file %<%s%>: %s", + path.c_str (), xstrerror (errno)); + fclose (nfd); + return; + } + + if (!buf.empty ()) + if (fwrite (buf.c_str (), buf.size (), 1, nfd) < 1) + { + rust_error_at (Location (), "failed to write to file %<%s%>: %s", + path.c_str (), xstrerror (errno)); + fclose (nfd); + return; + } + + // done + fclose (nfd); +} + +bool +PublicInterface::is_crate_public (const HIR::VisItem &item) +{ + const HIR::Visibility &visibility = item.get_visibility (); + + bool is_public + = visibility.get_vis_type () == HIR::Visibility::VisType::PUBLIC; + bool has_path = !visibility.get_path ().is_error (); + + // FIXME this might be pub(crate) + // Arthur magic required here + + return is_public && !has_path; +} + +std::string +PublicInterface::expected_metadata_filename () +{ + auto mappings = Analysis::Mappings::get (); + + const std::string current_crate_name = mappings->get_current_crate_name (); + return current_crate_name + extension_path; +} + +} // namespace Metadata +} // namespace Rust diff --git a/gcc/rust/metadata/rust-export-metadata.h b/gcc/rust/metadata/rust-export-metadata.h new file mode 100644 index 00000000000..cbb6ecd65a6 --- /dev/null +++ b/gcc/rust/metadata/rust-export-metadata.h @@ -0,0 +1,85 @@ +// 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_EXPORT_METADATA_H +#define RUST_EXPORT_METADATA_H + +#include "rust-system.h" +#include "rust-hir-full-decls.h" +#include "rust-hir-map.h" + +namespace Rust { +namespace Metadata { + +static const char kMagicHeader[4] = {'G', 'R', 'S', 'T'}; +static const char kSzDelim[1] = {'$'}; + +class ExportContext +{ +public: + ExportContext (); + + ~ExportContext (); + + void push_module_scope (const HIR::Module &module); + + const HIR::Module &pop_module_scope (); + + void emit_trait (const HIR::Trait &trait); + + void emit_function (const HIR::Function &fn); + + const std::string &get_interface_buffer () const; + +private: + Analysis::Mappings *mappings; + + std::vector> module_stack; + std::string public_interface_buffer; +}; + +class PublicInterface +{ +public: + static void Export (HIR::Crate &crate); + + static void ExportTo (HIR::Crate &crate, const std::string &output_path); + + static bool is_crate_public (const HIR::VisItem &item); + + static std::string expected_metadata_filename (); + +protected: + void gather_export_data (); + + void write_to_object_file () const; + + void write_to_path (const std::string &path) const; + +private: + PublicInterface (HIR::Crate &crate); + + HIR::Crate &crate; + Analysis::Mappings &mappings; + ExportContext context; +}; + +} // namespace Metadata +} // namespace Rust + +#endif // RUST_EXPORT_METADATA_H diff --git a/gcc/rust/metadata/rust-extern-crate.cc b/gcc/rust/metadata/rust-extern-crate.cc new file mode 100644 index 00000000000..614a6d91729 --- /dev/null +++ b/gcc/rust/metadata/rust-extern-crate.cc @@ -0,0 +1,173 @@ +// 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 +// . + +#include "rust-extern-crate.h" +#include "rust-diagnostics.h" +#include "rust-export-metadata.h" + +#include "md5.h" + +namespace Rust { +namespace Imports { + +ExternCrate::ExternCrate (Import::Stream &stream) : import_stream (stream) {} + +ExternCrate::~ExternCrate () {} + +bool +ExternCrate::ok () const +{ + return !import_stream.saw_error (); +} + +bool +ExternCrate::load (Location locus) +{ + // match header + import_stream.require_bytes (locus, Metadata::kMagicHeader, + sizeof (Metadata::kMagicHeader)); + if (import_stream.saw_error ()) + return false; + + // parse 16 bytes md5 + unsigned char checksum[16]; + bool ok + = import_stream.do_peek (sizeof (checksum), (const char **) &checksum); + if (!ok) + return false; + + import_stream.advance (sizeof (checksum)); + + // parse delim + import_stream.require_bytes (locus, Metadata::kSzDelim, + sizeof (Metadata::kSzDelim)); + if (import_stream.saw_error ()) + return false; + + // parse crate name + bool saw_delim = false; + while (!import_stream.saw_error () && !import_stream.at_eof ()) + { + unsigned char byte = import_stream.get_char (); + saw_delim + = memcmp (&byte, Metadata::kSzDelim, sizeof (Metadata::kSzDelim)) == 0; + if (saw_delim) + break; + + crate_name += byte; + } + if (!saw_delim || crate_name.empty ()) + { + import_stream.set_saw_error (); + rust_error_at (locus, "failed to read crate name field"); + + return false; + } + + // read until delim which is the size of the meta data + std::string metadata_length_buffer; + saw_delim = false; + while (!import_stream.saw_error () && !import_stream.at_eof ()) + { + unsigned char byte = import_stream.get_char (); + saw_delim + = memcmp (&byte, Metadata::kSzDelim, sizeof (Metadata::kSzDelim)) == 0; + if (saw_delim) + break; + + metadata_length_buffer += byte; + } + if (!saw_delim || metadata_length_buffer.empty ()) + { + import_stream.set_saw_error (); + rust_error_at (locus, "failed to read metatadata size"); + + return false; + } + + // interpret the string size + int expected_buffer_length = -1; + ok = ExternCrate::string_to_int (locus, metadata_length_buffer, false, + &expected_buffer_length); + if (!ok) + return false; + + // read the parsed size and it should be eof + metadata_buffer.reserve (expected_buffer_length); + for (int i = 0; i < expected_buffer_length && !import_stream.saw_error () + && !import_stream.at_eof (); + i++) + { + metadata_buffer += import_stream.get_char (); + } + + // compute the md5 + struct md5_ctx chksm; + unsigned char computed_checksum[16]; + + md5_init_ctx (&chksm); + md5_process_bytes (metadata_buffer.c_str (), metadata_buffer.size (), &chksm); + md5_finish_ctx (&chksm, computed_checksum); + + // FIXME i think the encoding and decoding of md5 is going wrong or else we + // are not computing it correctly + // + // compare the checksums + // if (memcmp(computed_checksum, checksum, sizeof (checksum)) != 0) + // { + // rust_error_at (locus, + // "checksum mismatch in metadata: %<%.*s%> vs %<%.*s%>", + // sizeof (computed_checksum), computed_checksum, + // sizeof (checksum), checksum); + // return false; + // } + + // all good + return true; +} + +const std::string & +ExternCrate::get_crate_name () const +{ + return crate_name; +} + +const std::string & +ExternCrate::get_metadata () const +{ + return metadata_buffer; +} + +// Turn a string into a integer with appropriate error handling. +bool +ExternCrate::string_to_int (Location locus, const std::string &s, + bool is_neg_ok, int *ret) +{ + char *end; + long prio = strtol (s.c_str (), &end, 10); + if (*end != '\0' || prio > 0x7fffffff || (prio < 0 && !is_neg_ok)) + { + rust_error_at (locus, "invalid integer in import data"); + return false; + } + *ret = prio; + return true; +} + +} // namespace Imports +} // namespace Rust diff --git a/gcc/rust/metadata/rust-extern-crate.h b/gcc/rust/metadata/rust-extern-crate.h new file mode 100644 index 00000000000..66da83894c1 --- /dev/null +++ b/gcc/rust/metadata/rust-extern-crate.h @@ -0,0 +1,55 @@ +// 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_EXTERN_CRATE_H +#define RUST_EXTERN_CRATE_H + +#include "rust-system.h" +#include "rust-imports.h" + +namespace Rust { +namespace Imports { + +class ExternCrate +{ +public: + ExternCrate (Import::Stream &stream); + ~ExternCrate (); + + bool ok () const; + + bool load (Location locus); + + const std::string &get_crate_name () const; + + const std::string &get_metadata () const; + + static bool string_to_int (Location locus, const std::string &s, + bool is_neg_ok, int *ret); + +private: + Import::Stream &import_stream; + + std::string crate_name; + std::string metadata_buffer; +}; + +} // namespace Imports +} // namespace Rust + +#endif // RUST_EXTERN_CRATE_H diff --git a/gcc/rust/metadata/rust-import-archive.cc b/gcc/rust/metadata/rust-import-archive.cc new file mode 100644 index 00000000000..5678d486f17 --- /dev/null +++ b/gcc/rust/metadata/rust-import-archive.cc @@ -0,0 +1,885 @@ +// import-archive.cc -- Go frontend read import data from an archive file. + +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "rust-system.h" +#include "rust-diagnostics.h" +#include "rust-imports.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +// Archive magic numbers. + +static const char armag[] = {'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}; +static const char armagt[] = {'!', '<', 't', 'h', 'i', 'n', '>', '\n'}; +static const char armagb[] = {'<', 'b', 'i', 'g', 'a', 'f', '>', '\n'}; +static const char arfmag[2] = {'`', '\n'}; + +namespace Rust { + +// Archive fixed length header for AIX big format. + +struct Archive_fl_header +{ + // Archive magic string. + char fl_magic[8]; + // Offset to member table. + char fl_memoff[20]; + // Offset to global symbol table. + char fl_gstoff[20]; + // Offset to global symbol table for 64-bit objects. + char fl_gst64off[20]; + // Offset to first archive member. + char fl_fstmoff[20]; + // Offset to last archive member. + char fl_lstmoff[20]; + // Offset to first member on free list. + char fl_freeoff[20]; +}; + +// The header of an entry in an archive. This is all readable text, +// padded with spaces where necesary. + +struct Archive_header +{ + // The entry name. + char ar_name[16]; + // The file modification time. + char ar_date[12]; + // The user's UID in decimal. + char ar_uid[6]; + // The user's GID in decimal. + char ar_gid[6]; + // The file mode in octal. + char ar_mode[8]; + // The file size in decimal. + char ar_size[10]; + // The final magic code. + char ar_fmag[2]; +}; + +// The header of an entry in an AIX big archive. +// This is followed by ar_namlen bytes + 2 bytes for arfmag. + +struct Archive_big_header +{ + // The file size in decimal. + char ar_size[20]; + // The next member offset in decimal. + char ar_nxtmem[20]; + // The previous member offset in decimal. + char ar_prvmem[20]; + // The file modification time in decimal. + char ar_date[12]; + // The user's UID in decimal. + char ar_uid[12]; + // The user's GID in decimal. + char ar_gid[12]; + // The file mode in octal. + char ar_mode[12]; + // The file name length in decimal. + char ar_namlen[4]; +}; + +// Return true if BYTES, which are from the start of the file, are an +// archive magic number. + +bool +Import::is_archive_magic (const char *bytes) +{ + const int archive_magic_len = 8; + return (memcmp (bytes, armag, archive_magic_len) == 0 + || memcmp (bytes, armagt, archive_magic_len) == 0 + || memcmp (bytes, armagb, archive_magic_len) == 0); +} + +// An object used to read an archive file. + +class Archive_file +{ +public: + Archive_file (const std::string &filename, int fd, Location location) + : filename_ (filename), fd_ (fd), filesize_ (-1), first_member_offset_ (0), + extended_names_ (), is_thin_archive_ (false), is_big_archive_ (false), + location_ (location), nested_archives_ () + {} + + // Initialize. + bool initialize (); + + // Return the file name. + const std::string &filename () const { return this->filename_; } + + // Get the file size. + off_t filesize () const { return this->filesize_; } + + // Return the offset of the first member. + off_t first_member_offset () const { return this->first_member_offset_; } + + // Return whether this is a thin archive. + bool is_thin_archive () const { return this->is_thin_archive_; } + + // Return whether this is a big archive. + bool is_big_archive () const { return this->is_big_archive_; } + + // Return the location of the import statement. + Location location () const { return this->location_; } + + // Read bytes. + bool read (off_t offset, off_t size, char *); + + // Parse a decimal in readable text. + bool parse_decimal (const char *str, off_t size, long *res) const; + + // Read the archive header at OFF, setting *PNAME, *SIZE, + // *NESTED_OFF and *NEXT_OFF. + bool read_header (off_t off, std::string *pname, off_t *size, + off_t *nested_off, off_t *next_off); + + // Interpret the header of HDR, the header of the archive member at + // file offset OFF. Return whether it succeeded. Set *SIZE to the + // size of the member. Set *PNAME to the name of the member. Set + // *NESTED_OFF to the offset in a nested archive. + bool interpret_header (const Archive_header *hdr, off_t off, + std::string *pname, off_t *size, + off_t *nested_off) const; + + // Get the file and offset for an archive member. + bool get_file_and_offset (off_t off, const std::string &hdrname, + off_t nested_off, int *memfd, off_t *memoff, + std::string *memname); + +private: + // Initialize a big archive (AIX) + bool initialize_big_archive (); + + // Initialize a normal archive + bool initialize_archive (); + + // Read the big archive header at OFF, setting *PNAME, *SIZE and *NEXT_OFF. + bool read_big_archive_header (off_t off, std::string *pname, off_t *size, + off_t *next_off); + + // Read the normal archive header at OFF, setting *PNAME, *SIZE, + // *NESTED_OFF and *NEXT_OFF. + bool read_archive_header (off_t off, std::string *pname, off_t *size, + off_t *nested_off, off_t *next_off); + + // For keeping track of open nested archives in a thin archive file. + typedef std::map Nested_archive_table; + + // The name of the file. + std::string filename_; + // The file descriptor. + int fd_; + // The file size; + off_t filesize_; + // The first member offset; + off_t first_member_offset_; + // The extended name table. + std::string extended_names_; + // Whether this is a thin archive. + bool is_thin_archive_; + // Whether this is a big archive. + bool is_big_archive_; + // The location of the import statements. + Location location_; + // Table of nested archives. + Nested_archive_table nested_archives_; +}; + +bool +Archive_file::initialize () +{ + struct stat st; + if (fstat (this->fd_, &st) < 0) + { + rust_error_at (this->location_, "%s: %m", this->filename_.c_str ()); + return false; + } + this->filesize_ = st.st_size; + + char buf[sizeof (armagt)]; + if (::lseek (this->fd_, 0, SEEK_SET) < 0 + || ::read (this->fd_, buf, sizeof (armagt)) != sizeof (armagt)) + { + rust_error_at (this->location_, "%s: %m", this->filename_.c_str ()); + return false; + } + if (memcmp (buf, armagt, sizeof (armagt)) == 0) + this->is_thin_archive_ = true; + else if (memcmp (buf, armagb, sizeof (armagb)) == 0) + this->is_big_archive_ = true; + + if (this->is_big_archive_) + return this->initialize_big_archive (); + else + return this->initialize_archive (); +} + +// Initialize a big archive (AIX). + +bool +Archive_file::initialize_big_archive () +{ + Archive_fl_header flhdr; + + // Read the fixed length header. + if (::lseek (this->fd_, 0, SEEK_SET) < 0 + || ::read (this->fd_, &flhdr, sizeof (flhdr)) != sizeof (flhdr)) + { + rust_error_at (this->location_, "%s: could not read archive header", + this->filename_.c_str ()); + return false; + } + + // Parse offset of the first member. + long off; + if (!this->parse_decimal (flhdr.fl_fstmoff, sizeof (flhdr.fl_fstmoff), &off)) + { + char *buf = new char[sizeof (flhdr.fl_fstmoff) + 1]; + memcpy (buf, flhdr.fl_fstmoff, sizeof (flhdr.fl_fstmoff)); + rust_error_at (this->location_, + ("%s: malformed first member offset in archive header" + " (expected decimal, got %s)"), + this->filename_.c_str (), buf); + delete[] buf; + return false; + } + if (off == 0) // Empty archive. + this->first_member_offset_ = this->filesize_; + else + this->first_member_offset_ = off; + return true; +} + +// Initialize a normal archive. + +bool +Archive_file::initialize_archive () +{ + this->first_member_offset_ = sizeof (armag); + if (this->first_member_offset_ == this->filesize_) + { + // Empty archive. + return true; + } + + // Look for the extended name table. + std::string filename; + off_t size; + off_t next_off; + if (!this->read_header (this->first_member_offset_, &filename, &size, NULL, + &next_off)) + return false; + if (filename.empty ()) + { + // We found the symbol table. + if (!this->read_header (next_off, &filename, &size, NULL, NULL)) + filename.clear (); + } + if (filename == "/") + { + char *rdbuf = new char[size]; + if (::read (this->fd_, rdbuf, size) != size) + { + rust_error_at (this->location_, "%s: could not read extended names", + filename.c_str ()); + delete[] rdbuf; + return false; + } + this->extended_names_.assign (rdbuf, size); + delete[] rdbuf; + } + + return true; +} + +// Read bytes from the file. + +bool +Archive_file::read (off_t offset, off_t size, char *buf) +{ + if (::lseek (this->fd_, offset, SEEK_SET) < 0 + || ::read (this->fd_, buf, size) != size) + { + rust_error_at (this->location_, "%s: %m", this->filename_.c_str ()); + return false; + } + return true; +} + +// Parse a decimal in readable text. + +bool +Archive_file::parse_decimal (const char *str, off_t size, long *res) const +{ + char *buf = new char[size + 1]; + memcpy (buf, str, size); + char *ps = buf + size; + while (ps > buf && ps[-1] == ' ') + --ps; + *ps = '\0'; + + errno = 0; + char *end; + *res = strtol (buf, &end, 10); + if (*end != '\0' || *res < 0 || (*res == LONG_MAX && errno == ERANGE)) + { + delete[] buf; + return false; + } + delete[] buf; + return true; +} + +// Read the header at OFF. Set *PNAME to the name, *SIZE to the size, +// *NESTED_OFF to the nested offset, and *NEXT_OFF to the next member offset. + +bool +Archive_file::read_header (off_t off, std::string *pname, off_t *size, + off_t *nested_off, off_t *next_off) +{ + if (::lseek (this->fd_, off, SEEK_SET) < 0) + { + rust_error_at (this->location_, "%s: %m", this->filename_.c_str ()); + return false; + } + if (this->is_big_archive_) + return this->read_big_archive_header (off, pname, size, next_off); + else + return this->read_archive_header (off, pname, size, nested_off, next_off); +} + +// Read the big archive header at OFF, setting *PNAME, *SIZE and *NEXT_OFF. + +bool +Archive_file::read_big_archive_header (off_t off, std::string *pname, + off_t *size, off_t *next_off) +{ + Archive_big_header hdr; + ssize_t got; + + got = ::read (this->fd_, &hdr, sizeof hdr); + if (got != sizeof hdr) + { + if (got < 0) + rust_error_at (this->location_, "%s: %m", this->filename_.c_str ()); + else if (got > 0) + rust_error_at (this->location_, "%s: short entry header at %ld", + this->filename_.c_str (), static_cast (off)); + else + rust_error_at (this->location_, "%s: unexpected EOF at %ld", + this->filename_.c_str (), static_cast (off)); + } + + long local_size; + if (!this->parse_decimal (hdr.ar_size, sizeof (hdr.ar_size), &local_size)) + { + char *buf = new char[sizeof (hdr.ar_size) + 1]; + memcpy (buf, hdr.ar_size, sizeof (hdr.ar_size)); + rust_error_at (this->location_, + ("%s: malformed size in entry header at %ld" + " (expected decimal, got %s)"), + this->filename_.c_str (), static_cast (off), buf); + delete[] buf; + return false; + } + *size = local_size; + + long namlen; + if (!this->parse_decimal (hdr.ar_namlen, sizeof (hdr.ar_namlen), &namlen)) + { + char *buf = new char[sizeof (hdr.ar_namlen) + 1]; + memcpy (buf, hdr.ar_namlen, sizeof (hdr.ar_namlen)); + rust_error_at (this->location_, + ("%s: malformed name length in entry header at %ld" + " (expected decimal, got %s)"), + this->filename_.c_str (), static_cast (off), buf); + delete[] buf; + return false; + } + // Read member name following member header. + char *rdbuf = new char[namlen]; + got = ::read (this->fd_, rdbuf, namlen); + if (got != namlen) + { + rust_error_at (this->location_, + "%s: malformed member name in entry header at %ld", + this->filename_.c_str (), static_cast (off)); + delete[] rdbuf; + return false; + } + pname->assign (rdbuf, namlen); + delete[] rdbuf; + + long local_next_off; + if (!this->parse_decimal (hdr.ar_nxtmem, sizeof (hdr.ar_nxtmem), + &local_next_off)) + { + char *buf = new char[sizeof (hdr.ar_nxtmem) + 1]; + memcpy (buf, hdr.ar_nxtmem, sizeof (hdr.ar_nxtmem)); + rust_error_at (this->location_, + ("%s: malformed next member offset in entry header at %ld" + " (expected decimal, got %s)"), + this->filename_.c_str (), static_cast (off), buf); + delete[] buf; + return false; + } + if (next_off != NULL) + { + if (local_next_off == 0) // Last member. + *next_off = this->filesize_; + else + *next_off = local_next_off; + } + return true; +} + +// Read the normal archive header at OFF, setting *PNAME, *SIZE, +// *NESTED_OFF and *NEXT_OFF. + +bool +Archive_file::read_archive_header (off_t off, std::string *pname, off_t *size, + off_t *nested_off, off_t *next_off) +{ + Archive_header hdr; + ssize_t got = ::read (this->fd_, &hdr, sizeof hdr); + if (got != sizeof hdr) + { + if (got < 0) + rust_error_at (this->location_, "%s: %m", this->filename_.c_str ()); + else if (got > 0) + rust_error_at (this->location_, "%s: short archive header at %ld", + this->filename_.c_str (), static_cast (off)); + else + rust_error_at (this->location_, "%s: unexpected EOF at %ld", + this->filename_.c_str (), static_cast (off)); + } + off_t local_nested_off; + if (!this->interpret_header (&hdr, off, pname, size, &local_nested_off)) + return false; + if (nested_off != NULL) + *nested_off = local_nested_off; + + off_t local_next_off; + local_next_off = off + sizeof (Archive_header); + if (!this->is_thin_archive_ || pname->empty () || *pname == "/") + local_next_off += *size; + if ((local_next_off & 1) != 0) + ++local_next_off; + if (local_next_off > this->filesize_) // Last member. + local_next_off = this->filesize_; + if (next_off != NULL) + *next_off = local_next_off; + return true; +} + +// Interpret the header of HDR, the header of the archive member at +// file offset OFF. + +bool +Archive_file::interpret_header (const Archive_header *hdr, off_t off, + std::string *pname, off_t *size, + off_t *nested_off) const +{ + if (memcmp (hdr->ar_fmag, arfmag, sizeof arfmag) != 0) + { + rust_error_at (this->location_, "%s: malformed archive header at %lu", + this->filename_.c_str (), + static_cast (off)); + return false; + } + + long local_size; + if (!this->parse_decimal (hdr->ar_size, sizeof hdr->ar_size, &local_size)) + { + rust_error_at (this->location_, + "%s: malformed archive header size at %lu", + this->filename_.c_str (), + static_cast (off)); + return false; + } + *size = local_size; + + *nested_off = 0; + if (hdr->ar_name[0] != '/') + { + const char *name_end = strchr (hdr->ar_name, '/'); + if (name_end == NULL + || name_end - hdr->ar_name >= static_cast (sizeof hdr->ar_name)) + { + rust_error_at (this->location_, + "%s: malformed archive header name at %lu", + this->filename_.c_str (), + static_cast (off)); + return false; + } + pname->assign (hdr->ar_name, name_end - hdr->ar_name); + } + else if (hdr->ar_name[1] == ' ') + { + // This is the symbol table. + pname->clear (); + } + else if (hdr->ar_name[1] == 'S' && hdr->ar_name[2] == 'Y' + && hdr->ar_name[3] == 'M' && hdr->ar_name[4] == '6' + && hdr->ar_name[5] == '4' && hdr->ar_name[6] == '/' + && hdr->ar_name[7] == ' ') + { + // 64-bit symbol table. + pname->clear (); + } + else if (hdr->ar_name[1] == '/') + { + // This is the extended name table. + pname->assign (1, '/'); + } + else + { + char *end; + errno = 0; + long x = strtol (hdr->ar_name + 1, &end, 10); + long y = 0; + if (*end == ':') + y = strtol (end + 1, &end, 10); + if (*end != ' ' || x < 0 || (x == LONG_MAX && errno == ERANGE) + || static_cast (x) >= this->extended_names_.size ()) + { + rust_error_at (this->location_, "%s: bad extended name index at %lu", + this->filename_.c_str (), + static_cast (off)); + return false; + } + + const char *name = this->extended_names_.data () + x; + const char *name_end = strchr (name, '\n'); + if (static_cast (name_end - name) > this->extended_names_.size () + || name_end[-1] != '/') + { + rust_error_at (this->location_, + "%s: bad extended name entry at header %lu", + this->filename_.c_str (), + static_cast (off)); + return false; + } + pname->assign (name, name_end - 1 - name); + *nested_off = y; + } + + return true; +} + +// Get the file and offset for an archive member. + +bool +Archive_file::get_file_and_offset (off_t off, const std::string &hdrname, + off_t nested_off, int *memfd, off_t *memoff, + std::string *memname) +{ + if (this->is_big_archive_) + { + *memfd = this->fd_; + *memoff = (off + sizeof (Archive_big_header) + hdrname.length () + + sizeof (arfmag)); + if ((*memoff & 1) != 0) + ++*memoff; + *memname = this->filename_ + '(' + hdrname + ')'; + return true; + } + else if (!this->is_thin_archive_) + { + *memfd = this->fd_; + *memoff = off + sizeof (Archive_header); + *memname = this->filename_ + '(' + hdrname + ')'; + return true; + } + + std::string filename = hdrname; + if (!IS_ABSOLUTE_PATH (filename.c_str ())) + { + const char *archive_path = this->filename_.c_str (); + const char *basename = lbasename (archive_path); + if (basename > archive_path) + filename.replace (0, 0, + this->filename_.substr (0, basename - archive_path)); + } + + if (nested_off > 0) + { + // This is a member of a nested archive. + Archive_file *nfile; + Nested_archive_table::const_iterator p + = this->nested_archives_.find (filename); + if (p != this->nested_archives_.end ()) + nfile = p->second; + else + { + int nfd = open (filename.c_str (), O_RDONLY | O_BINARY); + if (nfd < 0) + { + rust_error_at (this->location_, + "%s: cannot open nested archive %s", + this->filename_.c_str (), filename.c_str ()); + return false; + } + nfile = new Archive_file (filename, nfd, this->location_); + if (!nfile->initialize ()) + { + delete nfile; + return false; + } + this->nested_archives_[filename] = nfile; + } + + std::string nname; + off_t nsize; + off_t nnested_off; + if (!nfile->read_header (nested_off, &nname, &nsize, &nnested_off, NULL)) + return false; + return nfile->get_file_and_offset (nested_off, nname, nnested_off, memfd, + memoff, memname); + } + + // An external member of a thin archive. + *memfd = open (filename.c_str (), O_RDONLY | O_BINARY); + if (*memfd < 0) + { + rust_error_at (this->location_, "%s: %m", filename.c_str ()); + return false; + } + *memoff = 0; + *memname = filename; + return true; +} + +// An archive member iterator. This is more-or-less copied from gold. + +class Archive_iterator +{ +public: + // The header of an archive member. This is what this iterator + // points to. + struct Header + { + // The name of the member. + std::string name; + // The file offset of the member. + off_t off; + // The file offset of a nested archive member. + off_t nested_off; + // The size of the member. + off_t size; + }; + + Archive_iterator (Archive_file *afile, off_t off) : afile_ (afile), off_ (off) + { + this->read_next_header (); + } + + const Header &operator* () const { return this->header_; } + + const Header *operator-> () const { return &this->header_; } + + Archive_iterator &operator++ () + { + if (this->off_ == this->afile_->filesize ()) + return *this; + this->off_ = this->next_off_; + this->read_next_header (); + return *this; + } + + Archive_iterator operator++ (int) + { + Archive_iterator ret = *this; + ++*this; + return ret; + } + + bool operator== (const Archive_iterator &p) const + { + return this->off_ == p->off; + } + + bool operator!= (const Archive_iterator &p) const + { + return this->off_ != p->off; + } + +private: + void read_next_header (); + + // The underlying archive file. + Archive_file *afile_; + // The current offset in the file. + off_t off_; + // The offset of the next member. + off_t next_off_; + // The current archive header. + Header header_; +}; + +// Read the next archive header. + +void +Archive_iterator::read_next_header () +{ + off_t filesize = this->afile_->filesize (); + while (true) + { + if (this->off_ == filesize) + { + this->header_.off = filesize; + return; + } + + if (!this->afile_->read_header (this->off_, &this->header_.name, + &this->header_.size, + &this->header_.nested_off, + &this->next_off_)) + { + this->header_.off = filesize; + this->off_ = filesize; + return; + } + this->header_.off = this->off_; + + // Skip special members. + if (!this->header_.name.empty () && this->header_.name != "/") + return; + + this->off_ = this->next_off_; + } +} + +// Initial iterator. + +Archive_iterator +archive_begin (Archive_file *afile) +{ + return Archive_iterator (afile, afile->first_member_offset ()); +} + +// Final iterator. + +Archive_iterator +archive_end (Archive_file *afile) +{ + return Archive_iterator (afile, afile->filesize ()); +} + +// A type of Import_stream which concatenates other Import_streams +// together. + +class Stream_concatenate : public Import::Stream +{ +public: + Stream_concatenate () : inputs_ () {} + + // Add a new stream. + void add (Import::Stream *is) { this->inputs_.push_back (is); } + +protected: + bool do_peek (size_t, const char **); + + void do_advance (size_t); + +private: + std::list inputs_; +}; + +// Peek ahead. + +bool +Stream_concatenate::do_peek (size_t length, const char **bytes) +{ + while (true) + { + if (this->inputs_.empty ()) + return false; + if (this->inputs_.front ()->peek (length, bytes)) + return true; + delete this->inputs_.front (); + this->inputs_.pop_front (); + } +} + +// Advance. + +void +Stream_concatenate::do_advance (size_t skip) +{ + while (true) + { + if (this->inputs_.empty ()) + return; + if (!this->inputs_.front ()->at_eof ()) + { + // We just assume that this will do the right thing. It + // should be OK since we should never want to skip past + // multiple streams. + this->inputs_.front ()->advance (skip); + return; + } + delete this->inputs_.front (); + this->inputs_.pop_front (); + } +} + +// Import data from an archive. We walk through the archive and +// import data from each member. + +Import::Stream * +Import::find_archive_export_data (const std::string &filename, int fd, + Location location) +{ + Archive_file afile (filename, fd, location); + if (!afile.initialize ()) + return NULL; + + Stream_concatenate *ret = new Stream_concatenate; + + bool any_data = false; + bool any_members = false; + Archive_iterator pend = archive_end (&afile); + for (Archive_iterator p = archive_begin (&afile); p != pend; p++) + { + any_members = true; + int member_fd; + off_t member_off; + std::string member_name; + if (!afile.get_file_and_offset (p->off, p->name, p->nested_off, + &member_fd, &member_off, &member_name)) + return NULL; + + Import::Stream *is + = Import::find_object_export_data (member_name, member_fd, member_off, + location); + if (is != NULL) + { + ret->add (is); + any_data = true; + } + } + + if (!any_members) + { + // It's normal to have an empty archive file when using gobuild. + return new Stream_from_string (""); + } + + if (!any_data) + { + delete ret; + return NULL; + } + + return ret; +} + +} // namespace Rust diff --git a/gcc/rust/metadata/rust-imports.cc b/gcc/rust/metadata/rust-imports.cc new file mode 100644 index 00000000000..b44165b1fa2 --- /dev/null +++ b/gcc/rust/metadata/rust-imports.cc @@ -0,0 +1,441 @@ +// 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 +// . + +#include "rust-system.h" +#include "rust-diagnostics.h" +#include "rust-imports.h" +#include "rust-object-export.h" +#include "rust-export-metadata.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +namespace Rust { + +// The list of paths we search for import files. +static std::vector search_path; + +// Add a directory to the search path. This is called from the option +// handling language hook. +void +add_search_path (const std::string &path) +{ + search_path.push_back (path); +} + +// Find import data. This searches the file system for FILENAME and +// returns a pointer to a Stream object to read the data that it +// exports. If the file is not found, it returns NULL. + +// When FILENAME is not an absolute path and does not start with ./ or +// ../, we use the search path provided by -I and -L options. + +// When FILENAME does start with ./ or ../, we use +// RELATIVE_IMPORT_PATH as a prefix. + +// When FILENAME does not exist, we try modifying FILENAME to find the +// file. We use the first of these which exists: +// * We append ".gox". +// * We turn the base of FILENAME into libFILENAME.so. +// * We turn the base of FILENAME into libFILENAME.a. +// * We append ".o". + +// When using a search path, we apply each of these transformations at +// each entry on the search path before moving on to the next entry. +// If the file exists, but does not contain any Go export data, we +// stop; we do not keep looking for another file with the same name +// later in the search path. + +Import::Stream * +Import::open_package (const std::string &filename, Location location, + const std::string &relative_import_path) +{ + bool is_local; + if (IS_ABSOLUTE_PATH (filename)) + is_local = true; + else if (filename[0] == '.' + && (filename[1] == '\0' || IS_DIR_SEPARATOR (filename[1]))) + is_local = true; + else if (filename[0] == '.' && filename[1] == '.' + && (filename[2] == '\0' || IS_DIR_SEPARATOR (filename[2]))) + is_local = true; + else + is_local = false; + + std::string fn = filename; + if (is_local && !IS_ABSOLUTE_PATH (filename) + && !relative_import_path.empty ()) + { + if (fn == ".") + { + // A special case. + fn = relative_import_path; + } + else if (fn[0] == '.' && fn[1] == '.' + && (fn[2] == '\0' || IS_DIR_SEPARATOR (fn[2]))) + { + // We are going to join relative_import_path and fn, and it + // will look like DIR/../PATH. But DIR does not necessarily + // exist in this case, and if it doesn't the use of .. will + // fail although it shouldn't. The gc compiler uses + // path.Join here, which cleans up the .., so we need to do + // the same. + size_t index; + for (index = relative_import_path.length () - 1; + index > 0 && !IS_DIR_SEPARATOR (relative_import_path[index]); + index--) + ; + if (index > 0) + fn = relative_import_path.substr (0, index) + fn.substr (2); + else + fn = relative_import_path + '/' + fn; + } + else + fn = relative_import_path + '/' + fn; + is_local = false; + } + + if (!is_local) + { + for (std::vector::const_iterator p = search_path.begin (); + p != search_path.end (); ++p) + { + std::string indir = *p; + if (!indir.empty () && indir[indir.size () - 1] != '/') + indir += '/'; + indir += fn; + Stream *s = Import::try_package_in_directory (indir, location); + if (s != NULL) + return s; + } + } + + Stream *s = Import::try_package_in_directory (fn, location); + if (s != NULL) + return s; + + return NULL; +} + +// Try to find the export data for FILENAME. + +Import::Stream * +Import::try_package_in_directory (const std::string &filename, + Location location) +{ + std::string found_filename = filename; + int fd = open (found_filename.c_str (), O_RDONLY | O_BINARY); + + if (fd >= 0) + { + struct stat s; + if (fstat (fd, &s) >= 0 && S_ISDIR (s.st_mode)) + { + close (fd); + fd = -1; + errno = EISDIR; + } + } + + if (fd < 0) + { + if (errno != ENOENT && errno != EISDIR) + rust_warning_at (location, 0, "%s: %m", filename.c_str ()); + + fd = Import::try_suffixes (&found_filename); + if (fd < 0) + return NULL; + } + + // The export data may not be in this file. + Stream *s = Import::find_export_data (found_filename, fd, location); + if (s != NULL) + return s; + + close (fd); + + rust_error_at (location, "%s exists but does not contain any Go export data", + found_filename.c_str ()); + + return NULL; +} + +// Given import "*PFILENAME", where *PFILENAME does not exist, try +// various suffixes. If we find one, set *PFILENAME to the one we +// found. Return the open file descriptor. + +int +Import::try_suffixes (std::string *pfilename) +{ + std::string filename = *pfilename + ".rox"; + int fd = open (filename.c_str (), O_RDONLY | O_BINARY); + if (fd >= 0) + { + *pfilename = filename; + return fd; + } + + const char *basename = lbasename (pfilename->c_str ()); + size_t basename_pos = basename - pfilename->c_str (); + filename = pfilename->substr (0, basename_pos) + "lib" + basename + ".so"; + fd = open (filename.c_str (), O_RDONLY | O_BINARY); + if (fd >= 0) + { + *pfilename = filename; + return fd; + } + + filename = pfilename->substr (0, basename_pos) + "lib" + basename + ".a"; + fd = open (filename.c_str (), O_RDONLY | O_BINARY); + if (fd >= 0) + { + *pfilename = filename; + return fd; + } + + filename = *pfilename + ".o"; + fd = open (filename.c_str (), O_RDONLY | O_BINARY); + if (fd >= 0) + { + *pfilename = filename; + return fd; + } + + return -1; +} + +// Look for export data in the file descriptor FD. + +Import::Stream * +Import::find_export_data (const std::string &filename, int fd, + Location location) +{ + // See if we can read this as an object file. + Import::Stream *stream + = Import::find_object_export_data (filename, fd, 0, location); + if (stream != NULL) + return stream; + + const int len = sizeof (Metadata::kMagicHeader); + if (lseek (fd, 0, SEEK_SET) < 0) + { + rust_error_at (location, "lseek %s failed: %m", filename.c_str ()); + return NULL; + } + + char buf[len]; + ssize_t c = ::read (fd, buf, len); + if (c < len) + return NULL; + + // Check for a file containing nothing but Go export data. + // if (memcmp (buf, Export::cur_magic, Export::magic_len) == 0 + // || memcmp (buf, Export::v1_magic, Export::magic_len) == 0 + // || memcmp (buf, Export::v2_magic, Export::magic_len) == 0) + // + // FIXME we need to work out a better header + // + if (memcmp (buf, Metadata::kMagicHeader, sizeof (Metadata::kMagicHeader)) + == 0) + return new Stream_from_file (fd); + + // See if we can read this as an archive. + if (Import::is_archive_magic (buf)) + return Import::find_archive_export_data (filename, fd, location); + + return NULL; +} + +// Look for export data in an object file. + +Import::Stream * +Import::find_object_export_data (const std::string &filename, int fd, + off_t offset, Location location) +{ + char *buf; + size_t len; + int err; + const char *errmsg = rust_read_export_data (fd, offset, &buf, &len, &err); + if (errmsg != NULL) + { + if (err == 0) + rust_error_at (location, "%s: %s", filename.c_str (), errmsg); + else + rust_error_at (location, "%s: %s: %s", filename.c_str (), errmsg, + xstrerror (err)); + return NULL; + } + + if (buf == NULL) + return NULL; + + return new Stream_from_buffer (buf, len); +} + +// Class Import. + +// Construct an Import object. We make the builtin_types_ vector +// large enough to hold all the builtin types. + +Import::Import (Stream *stream, Location location) + : stream_ (stream), location_ (location) +{} + +// Import the data in the associated stream. + +// Read LENGTH bytes from the stream. + +void +Import::read (size_t length, std::string *out) +{ + const char *data; + if (!this->stream_->peek (length, &data)) + { + if (!this->stream_->saw_error ()) + rust_error_at (this->location_, "import error at %d: expected %d bytes", + this->stream_->pos (), static_cast (length)); + this->stream_->set_saw_error (); + *out = std::string (""); + return; + } + *out = std::string (data, length); + this->advance (length); +} + +// Class Import::Stream. + +Import::Stream::Stream () : pos_ (0), saw_error_ (false) {} + +Import::Stream::~Stream () {} + +// Return the next character to come from the stream. + +int +Import::Stream::peek_char () +{ + const char *read; + if (!this->do_peek (1, &read)) + return -1; + // Make sure we return an unsigned char, so that we don't get + // confused by \xff. + unsigned char ret = *read; + return ret; +} + +// Return true if the next LENGTH characters from the stream match +// BYTES + +bool +Import::Stream::match_bytes (const char *bytes, size_t length) +{ + const char *read; + if (!this->do_peek (length, &read)) + return false; + return memcmp (bytes, read, length) == 0; +} + +// Require that the next LENGTH bytes from the stream match BYTES. + +void +Import::Stream::require_bytes (Location location, const char *bytes, + size_t length) +{ + const char *read; + if (!this->do_peek (length, &read) || memcmp (bytes, read, length) != 0) + { + if (!this->saw_error_) + rust_error_at (location, "import error at %d: expected %<%.*s%>", + this->pos (), static_cast (length), bytes); + this->saw_error_ = true; + return; + } + this->advance (length); +} + +// Class Stream_from_file. + +Stream_from_file::Stream_from_file (int fd) : fd_ (fd), data_ () +{ + if (lseek (fd, 0, SEEK_SET) != 0) + { + rust_fatal_error (Linemap::unknown_location (), "lseek failed: %m"); + this->set_saw_error (); + } +} + +Stream_from_file::~Stream_from_file () { close (this->fd_); } + +// Read next bytes. + +bool +Stream_from_file::do_peek (size_t length, const char **bytes) +{ + if (this->data_.length () >= length) + { + *bytes = this->data_.data (); + return true; + } + + this->data_.resize (length); + ssize_t got = ::read (this->fd_, &this->data_[0], length); + + if (got < 0) + { + if (!this->saw_error ()) + rust_fatal_error (Linemap::unknown_location (), "read failed: %m"); + this->set_saw_error (); + return false; + } + + if (lseek (this->fd_, -got, SEEK_CUR) < 0) + { + if (!this->saw_error ()) + rust_fatal_error (Linemap::unknown_location (), "lseek failed: %m"); + this->set_saw_error (); + return false; + } + + if (static_cast (got) < length) + return false; + + *bytes = this->data_.data (); + return true; +} + +// Advance. + +void +Stream_from_file::do_advance (size_t skip) +{ + if (lseek (this->fd_, skip, SEEK_CUR) < 0) + { + if (!this->saw_error ()) + rust_fatal_error (Linemap::unknown_location (), "lseek failed: %m"); + this->set_saw_error (); + } + if (!this->data_.empty ()) + { + if (this->data_.length () > skip) + this->data_.erase (0, skip); + else + this->data_.clear (); + } +} + +} // namespace Rust diff --git a/gcc/rust/metadata/rust-imports.h b/gcc/rust/metadata/rust-imports.h new file mode 100644 index 00000000000..51cc4fc7613 --- /dev/null +++ b/gcc/rust/metadata/rust-imports.h @@ -0,0 +1,257 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef RUST_IMPORTS_H +#define RUST_IMPORTS_H + +#include "rust-system.h" +#include "rust-location.h" + +namespace Rust { + +extern void +add_search_path (const std::string &path); + +class Import +{ +public: + // The Stream class is an interface used to read the data. The + // caller should instantiate a child of this class. + class Stream + { + public: + Stream (); + virtual ~Stream (); + + // Set the position, for error messages. + void set_pos (int pos) { this->pos_ = pos; } + + // Return whether we have seen an error. + bool saw_error () const { return this->saw_error_; } + + // Record that we've seen an error. + void set_saw_error () { this->saw_error_ = true; } + + // Return the next character (a value from 0 to 0xff) without + // advancing. Returns -1 at end of stream. + int peek_char (); + + // Look for LENGTH characters, setting *BYTES to point to them. + // Returns false if the bytes are not available. Does not + // advance. + bool peek (size_t length, const char **bytes) + { + return this->do_peek (length, bytes); + } + + // Return the next character (a value from 0 to 0xff) and advance + // the read position by 1. Returns -1 at end of stream. + int get_char () + { + int c = this->peek_char (); + this->advance (1); + return c; + } + + // Return true if at the end of the stream. + bool at_eof () { return this->peek_char () == -1; } + + // Return true if the next bytes match STR. + bool match_c_string (const char *str) + { + return this->match_bytes (str, strlen (str)); + } + + // Return true if the next LENGTH bytes match BYTES. + bool match_bytes (const char *bytes, size_t length); + + // Give an error if the next bytes do not match STR. Advance the + // read position by the length of STR. + void require_c_string (Location location, const char *str) + { + this->require_bytes (location, str, strlen (str)); + } + + // Given an error if the next LENGTH bytes do not match BYTES. + // Advance the read position by LENGTH. + void require_bytes (Location, const char *bytes, size_t length); + + // Advance the read position by SKIP bytes. + void advance (size_t skip) + { + this->do_advance (skip); + this->pos_ += skip; + } + + // Return the current read position. This returns int because it + // is more convenient in error reporting. FIXME. + int pos () { return static_cast (this->pos_); } + + // This function should set *BYTES to point to a buffer holding + // the LENGTH bytes at the current read position. It should + // return false if the bytes are not available. This should not + // change the current read position. + virtual bool do_peek (size_t length, const char **bytes) = 0; + + // This function should advance the current read position LENGTH + // bytes. + virtual void do_advance (size_t skip) = 0; + + private: + // The current read position. + size_t pos_; + // True if we've seen an error reading from this stream. + bool saw_error_; + }; + + // Find import data. This searches the file system for FILENAME and + // returns a pointer to a Stream object to read the data that it + // exports. LOCATION is the location of the import statement. + // RELATIVE_IMPORT_PATH is used as a prefix for a relative import. + static Stream *open_package (const std::string &filename, Location location, + const std::string &relative_import_path); + + // Constructor. + Import (Stream *, Location); + + // The location of the import statement. + Location location () const { return this->location_; } + + // Return the next character. + int peek_char () { return this->stream_->peek_char (); } + + // Return the next character and advance. + int get_char () { return this->stream_->get_char (); } + + // Read LENGTH characters into *OUT and advance past them. On + // EOF reports an error and sets *OUT to an empty string. + void read (size_t length, std::string *out); + + // Return true at the end of the stream. + bool at_eof () { return this->stream_->at_eof (); } + + // Return whether the next bytes match STR. + bool match_c_string (const char *str) + { + return this->stream_->match_c_string (str); + } + + // Require that the next bytes match STR. + void require_c_string (const char *str) + { + this->stream_->require_c_string (this->location_, str); + } + + // Advance the stream SKIP bytes. + void advance (size_t skip) { this->stream_->advance (skip); } + + // Stream position, for error reporting. + int pos () { return this->stream_->pos (); } + + // Clear the stream when it is no longer accessible. + void clear_stream () { this->stream_ = NULL; } + +private: + static Stream *try_package_in_directory (const std::string &, Location); + + static int try_suffixes (std::string *); + + static Stream *find_export_data (const std::string &filename, int fd, + Location); + + static Stream *find_object_export_data (const std::string &filename, int fd, + off_t offset, Location); + + static bool is_archive_magic (const char *); + + static Stream *find_archive_export_data (const std::string &filename, int fd, + Location); + + // The stream from which to read import data. + Stream *stream_; + // The location of the import statement we are processing. + Location location_; +}; + +// Read import data from a string. + +class Stream_from_string : public Import::Stream +{ +public: + Stream_from_string (const std::string &str) : str_ (str), pos_ (0) {} + + bool do_peek (size_t length, const char **bytes) + { + if (this->pos_ + length > this->str_.length ()) + return false; + *bytes = this->str_.data () + this->pos_; + return true; + } + + void do_advance (size_t len) { this->pos_ += len; } + +private: + // The string of data we are reading. + std::string str_; + // The current position within the string. + size_t pos_; +}; + +// Read import data from a buffer allocated using malloc. + +class Stream_from_buffer : public Import::Stream +{ +public: + Stream_from_buffer (char *buf, size_t length) + : buf_ (buf), length_ (length), pos_ (0) + {} + + ~Stream_from_buffer () { free (this->buf_); } + + bool do_peek (size_t length, const char **bytes) + { + if (this->pos_ + length > this->length_) + return false; + *bytes = this->buf_ + this->pos_; + return true; + } + + void do_advance (size_t len) { this->pos_ += len; } + +private: + // The data we are reading. + char *buf_; + // The length of the buffer. + size_t length_; + // The current position within the buffer. + size_t pos_; +}; + +// Read import data from an open file descriptor. + +class Stream_from_file : public Import::Stream +{ +public: + Stream_from_file (int fd); + + ~Stream_from_file (); + + bool do_peek (size_t, const char **); + + void do_advance (size_t); + +private: + // No copying. + Stream_from_file (const Stream_from_file &); + Stream_from_file &operator= (const Stream_from_file &); + + // The file descriptor. + int fd_; + // Data read from the file. + std::string data_; +}; + +} // namespace Rust + +#endif // RUST_IMPORTS_H diff --git a/gcc/rust/rust-object-export.cc b/gcc/rust/rust-object-export.cc new file mode 100644 index 00000000000..f3007289ead --- /dev/null +++ b/gcc/rust/rust-object-export.cc @@ -0,0 +1,177 @@ +/* rust-backend.c -- Rust frontend interface to gcc backend. + Copyright (C) 2010-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 "config.h" +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "tree.h" +#include "memmodel.h" +#include "tm_p.h" +#include "diagnostic.h" +#include "simple-object.h" +#include "stor-layout.h" +#include "intl.h" +#include "output.h" /* for assemble_string */ +#include "common/common-target.h" + +// satisfy intellisense +#include "options.h" + +/* The segment name we pass to simple_object_start_read to find Rust + export data. */ + +#ifndef RUST_EXPORT_SEGMENT_NAME +#define RUST_EXPORT_SEGMENT_NAME "__GNU_RUST" +#endif + +/* The section name we use when reading and writing export data. */ + +#ifndef RUST_EXPORT_SECTION_NAME +#define RUST_EXPORT_SECTION_NAME ".rust_export" +#endif + +#ifndef TARGET_AIX +#define TARGET_AIX 0 +#endif + +/* Return whether or not GCC has reported any errors. */ + +bool +saw_errors (void) +{ + return errorcount != 0 || sorrycount != 0; +} + +/* Return the alignment in bytes of a struct field of type T. */ + +unsigned int +rust_field_alignment (tree t) +{ + unsigned int v; + + v = TYPE_ALIGN (t); + +#ifdef BIGGEST_FIELD_ALIGNMENT + if (v > BIGGEST_FIELD_ALIGNMENT) + v = BIGGEST_FIELD_ALIGNMENT; +#endif + +#ifdef ADJUST_FIELD_ALIGN + v = ADJUST_FIELD_ALIGN (NULL_TREE, t, v); +#endif + + return v / BITS_PER_UNIT; +} + +/* This is called by the Rust frontend proper to add data to the + section containing Rust export data. */ + +void +rust_write_export_data (const char *bytes, unsigned int size) +{ + static section *sec; + + if (sec == NULL) + { + gcc_assert (targetm_common.have_named_sections); + sec = get_section (RUST_EXPORT_SECTION_NAME, + TARGET_AIX ? SECTION_EXCLUDE : SECTION_DEBUG, NULL); + } + + switch_to_section (sec); + assemble_string (bytes, size); +} + +/* The rust_read_export_data function is called by the Rust frontend + proper to read Rust export data from an object file. FD is a file + descriptor open for reading. OFFSET is the offset within the file + where the object file starts; this will be 0 except when reading an + archive. On success this returns NULL and sets *PBUF to a buffer + allocated using malloc, of size *PLEN, holding the export data. If + the data is not found, this returns NULL and sets *PBUF to NULL and + *PLEN to 0. If some error occurs, this returns an error message + and sets *PERR to an errno value or 0 if there is no relevant + errno. */ + +const char * +rust_read_export_data (int fd, off_t offset, char **pbuf, size_t *plen, + int *perr) +{ + simple_object_read *sobj; + const char *errmsg; + off_t sec_offset; + off_t sec_length; + int found; + char *buf; + ssize_t c; + + *pbuf = NULL; + *plen = 0; + + sobj = simple_object_start_read (fd, offset, RUST_EXPORT_SEGMENT_NAME, + &errmsg, perr); + if (sobj == NULL) + { + /* If we get an error here, just pretend that we didn't find any + export data. This is the right thing to do if the error is + that the file was not recognized as an object file. This + will ignore file I/O errors, but it's not too big a deal + because we will wind up giving some other error later. */ + return NULL; + } + + found = simple_object_find_section (sobj, RUST_EXPORT_SECTION_NAME, + &sec_offset, &sec_length, &errmsg, perr); + simple_object_release_read (sobj); + if (!found) + return errmsg; + + if (lseek (fd, offset + sec_offset, SEEK_SET) < 0) + { + *perr = errno; + return _ ("lseek failed while reading export data"); + } + + buf = XNEWVEC (char, sec_length); + if (buf == NULL) + { + *perr = errno; + return _ ("memory allocation failed while reading export data"); + } + + c = read (fd, buf, sec_length); + if (c < 0) + { + *perr = errno; + free (buf); + return _ ("read failed while reading export data"); + } + + if (c < sec_length) + { + free (buf); + return _ ("short read while reading export data"); + } + + *pbuf = buf; + *plen = sec_length; + + return NULL; +} diff --git a/gcc/rust/rust-object-export.h b/gcc/rust/rust-object-export.h new file mode 100644 index 00000000000..fcede54ae59 --- /dev/null +++ b/gcc/rust/rust-object-export.h @@ -0,0 +1,33 @@ +// 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_OBJECT_EXPORT_H +#define RUST_OBJECT_EXPORT_H + +#include "rust-system.h" + +extern unsigned int +rust_field_alignment (tree t); + +extern const char * +rust_read_export_data (int fd, off_t offset, char **pbuf, size_t *plen, + int *perr); +extern void +rust_write_export_data (const char *bytes, unsigned int size); + +#endif // RUST_OBJECT_EXPORT_H From patchwork Wed Aug 24 11:59:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 57004 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 22E703885C25 for ; Wed, 24 Aug 2022 12:07:59 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x335.google.com (mail-wm1-x335.google.com [IPv6:2a00:1450:4864:20::335]) by sourceware.org (Postfix) with ESMTPS id C5D9D38983A7; Wed, 24 Aug 2022 12:01:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C5D9D38983A7 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wm1-x335.google.com with SMTP id j26so8672098wms.0; Wed, 24 Aug 2022 05:01:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=1GU0BGkn1An4+1tOSI96NUta0y/eKG5nxnqZewIoLsQ=; b=lUNL9vmR4pJec2Jeotvr1JLFPMnqGc1QZwCipHpZBf+GOBrRt7owXIBsviePfkwi7q t1LhB/41nhyfOhDzmSc86ZpWGzyjZw0k6iehq7VtMc5wGzuvmlAUhDjXTGyX5VGUnZiA MLSK1UQ2lLBLHZ5NUznIycCvGUg0EEVo0V65vdvAepgszz60SEF55KVZuG4P8XDcu+O6 74q2t0HofylzNMnuKpdJThhTdFwkeZKSWhtbHv5IZHvbwWXrqCvCDIsktout3paA2GKS pFCiUZEfsM+G8sGPMT5EkqYNDbkyrIhgU28Wln2eHieEGgXLiBUCuA7hQG1eHnRhqrwR 4C2w== 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; bh=1GU0BGkn1An4+1tOSI96NUta0y/eKG5nxnqZewIoLsQ=; b=QMBXA02yIwWITzPMlKlVtMiBmUOAywnYNcoPc4PIM3R3xQI35d8XM8B0LJtMuhV11J 9RJh8RYCA9JtbyQVkHeO0velWoLhqBG4rIi3uPmFaxUrD84ICUam7x3FTXBA939ETJbY tS4dvlf1iCB1cp+oII1KZ13nfiuLdpLZeGHSJ2El+6lpg8l/Wpa0G3A+TNBxVkmA9e/a Czm8/N3L8ZOFDXeE+QPsv2Zzh4XTrmktMUpNa92dv1EB9JdaS/g3d8PxvsHcURpMFcCs VCM+mu/S9bhHZI38Y/Vt9+yaSEb6tR078DHu6NXcLjP08rqWzmi4lDG+HpshgOjwgbSd mtTw== X-Gm-Message-State: ACgBeo3ereB5WKGKqtSlBbbCItLTGl1RiEGy1rb2R9zl8YdhqN30a7Eq qFaNkksny4NtDSgZAEegvEyVrvLhv5o= X-Google-Smtp-Source: AA6agR5RItPhqulgRaH+AuGHh2g6vsy0zj+fhH3imOfg/dREeCLZH5zrV3g0H+Qcn43JLj3KUTy/0g== X-Received: by 2002:a05:600c:198e:b0:3a6:2a00:3df3 with SMTP id t14-20020a05600c198e00b003a62a003df3mr5089567wmq.79.1661342474526; Wed, 24 Aug 2022 05:01:14 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.01.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:01:14 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 30/37] gccrs: These are wrappers ported from reusing gccgo Date: Wed, 24 Aug 2022 12:59:49 +0100 Message-Id: <20220824115956.737931-31-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron The wrappers over linemap and location will eventually disappear here but served as a useful starting point for us. We have wrappers over the diagnostics system which we might be able to get rid of as well. --- gcc/rust/rust-diagnostics.cc | 244 +++++++++++++++++++++++++++++++ gcc/rust/rust-diagnostics.h | 154 +++++++++++++++++++ gcc/rust/rust-gcc-diagnostics.cc | 84 +++++++++++ gcc/rust/rust-linemap.cc | 229 +++++++++++++++++++++++++++++ gcc/rust/rust-linemap.h | 163 +++++++++++++++++++++ gcc/rust/rust-location.h | 105 +++++++++++++ gcc/rust/rust-system.h | 86 +++++++++++ 7 files changed, 1065 insertions(+) create mode 100644 gcc/rust/rust-diagnostics.cc create mode 100644 gcc/rust/rust-diagnostics.h create mode 100644 gcc/rust/rust-gcc-diagnostics.cc create mode 100644 gcc/rust/rust-linemap.cc create mode 100644 gcc/rust/rust-linemap.h create mode 100644 gcc/rust/rust-location.h create mode 100644 gcc/rust/rust-system.h diff --git a/gcc/rust/rust-diagnostics.cc b/gcc/rust/rust-diagnostics.cc new file mode 100644 index 00000000000..c2d3e4ee8be --- /dev/null +++ b/gcc/rust/rust-diagnostics.cc @@ -0,0 +1,244 @@ +// rust-diagnostics.cc -- GCC implementation of rust diagnostics interface. +// Copyright (C) 2016-2022 Free Software Foundation, Inc. +// Contributed by Than McIntosh, Google. + +// 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-diagnostics.h" + +static std::string +mformat_value () +{ + return std::string (xstrerror (errno)); +} + +// Rewrite a format string to expand any extensions not +// supported by sprintf(). See comments in rust-diagnostics.h +// for list of supported format specifiers. + +static std::string +expand_format (const char *fmt) +{ + std::stringstream ss; + for (const char *c = fmt; *c; ++c) + { + if (*c != '%') + { + ss << *c; + continue; + } + c++; + switch (*c) + { + case '\0': { + // malformed format string + rust_unreachable (); + } + case '%': { + ss << "%"; + break; + } + case 'm': { + ss << mformat_value (); + break; + } + case '<': { + ss << rust_open_quote (); + break; + } + case '>': { + ss << rust_close_quote (); + break; + } + case 'q': { + ss << rust_open_quote (); + c++; + if (*c == 'm') + { + ss << mformat_value (); + } + else + { + ss << "%" << *c; + } + ss << rust_close_quote (); + break; + } + default: { + ss << "%" << *c; + } + } + } + return ss.str (); +} + +// Expand message format specifiers, using a combination of +// expand_format above to handle extensions (ex: %m, %q) and vasprintf() +// to handle regular printf-style formatting. A pragma is being used here to +// suppress this warning: +// +// warning: function ‘std::__cxx11::string expand_message(const char*, +// __va_list_tag*)’ might be a candidate for ‘gnu_printf’ format attribute +// [-Wsuggest-attribute=format] +// +// What appears to be happening here is that the checker is deciding that +// because of the call to vasprintf() (which has attribute gnu_printf), the +// calling function must need to have attribute gnu_printf as well, even +// though there is already an attribute declaration for it. + +static std::string +expand_message (const char *fmt, va_list ap) RUST_ATTRIBUTE_GCC_DIAG (1, 0); + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsuggest-attribute=format" + +static std::string +expand_message (const char *fmt, va_list ap) +{ + char *mbuf = 0; + std::string expanded_fmt = expand_format (fmt); + int nwr = vasprintf (&mbuf, expanded_fmt.c_str (), ap); + if (nwr == -1) + { + // memory allocation failed + rust_be_error_at (Linemap::unknown_location (), + "memory allocation failed in vasprintf"); + rust_assert (0); + } + std::string rval = std::string (mbuf); + free (mbuf); + return rval; +} + +#pragma GCC diagnostic pop + +static const char *cached_open_quote = NULL; +static const char *cached_close_quote = NULL; + +const char * +rust_open_quote () +{ + if (cached_open_quote == NULL) + rust_be_get_quotechars (&cached_open_quote, &cached_close_quote); + return cached_open_quote; +} + +const char * +rust_close_quote () +{ + if (cached_close_quote == NULL) + rust_be_get_quotechars (&cached_open_quote, &cached_close_quote); + return cached_close_quote; +} + +void +rust_internal_error_at (const Location location, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + rust_be_internal_error_at (location, expand_message (fmt, ap)); + va_end (ap); +} + +void +rust_error_at (const Location location, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + rust_be_error_at (location, expand_message (fmt, ap)); + va_end (ap); +} + +void +rust_warning_at (const Location location, int opt, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + rust_be_warning_at (location, opt, expand_message (fmt, ap)); + va_end (ap); +} + +void +rust_fatal_error (const Location location, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + rust_be_fatal_error (location, expand_message (fmt, ap)); + va_end (ap); +} + +void +rust_inform (const Location location, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + rust_be_inform (location, expand_message (fmt, ap)); + va_end (ap); +} + +// Rich Locations +void +rust_error_at (const RichLocation &location, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + rust_be_error_at (location, expand_message (fmt, ap)); + va_end (ap); +} + +void +rust_debug_loc (const Location location, const char *fmt, ...) +{ + if (!rust_be_debug_p ()) + return; + + va_list ap; + + va_start (ap, fmt); + char *mbuf = NULL; + int nwr = vasprintf (&mbuf, fmt, ap); + va_end (ap); + if (nwr == -1) + { + rust_be_error_at (Linemap::unknown_location (), + "memory allocation failed in vasprintf"); + rust_assert (0); + } + std::string rval = std::string (mbuf); + free (mbuf); + rust_be_inform (location, rval); +} + +namespace Rust { +Error::Error (const Location location, const char *fmt, ...) : locus (location) +{ + va_list ap; + + va_start (ap, fmt); + message = expand_message (fmt, ap); + va_end (ap); + + message.shrink_to_fit (); +} +} // namespace Rust diff --git a/gcc/rust/rust-diagnostics.h b/gcc/rust/rust-diagnostics.h new file mode 100644 index 00000000000..93bd1b3237b --- /dev/null +++ b/gcc/rust/rust-diagnostics.h @@ -0,0 +1,154 @@ +// 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 +// . + +// rust-diagnostics.h -- interface to diagnostic reporting -*- C++ -*- + +#ifndef RUST_DIAGNOSTICS_H +#define RUST_DIAGNOSTICS_H + +#include "rust-linemap.h" + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) +#define RUST_ATTRIBUTE_GCC_DIAG(m, n) \ + __attribute__ ((__format__ (__gcc_tdiag__, m, n))) \ + __attribute__ ((__nonnull__ (m))) +#else +#define RUST_ATTRIBUTE_GCC_DIAG(m, n) +#endif + +// These declarations define the interface through which the frontend +// reports errors and warnings. These functions accept printf-like +// format specifiers (e.g. %d, %f, %s, etc), with the following additional +// extensions: +// +// 1. 'q' qualifier may be applied to a specifier to add quoting, e.g. +// %qd produces a quoted decimal output, %qs a quoted string output. +// [This extension is supported only with single-character format +// specifiers]. +// +// 2. %m specifier outputs value of "strerror(errno)" at time of call. +// +// 3. %< outputs an opening quote, %> a closing quote. +// +// All other format specifiers are as defined by 'sprintf'. The final resulting +// message is then sent to the back end via rust_be_error_at/rust_be_warning_at. + +// clang-format off +// simple location +extern void +rust_internal_error_at (const Location, const char *fmt, ...) + RUST_ATTRIBUTE_GCC_DIAG (2, 3) + RUST_ATTRIBUTE_NORETURN; +extern void +rust_error_at (const Location, const char *fmt, ...) + RUST_ATTRIBUTE_GCC_DIAG (2, 3); +extern void +rust_warning_at (const Location, int opt, const char *fmt, ...) + RUST_ATTRIBUTE_GCC_DIAG (3, 4); +extern void +rust_fatal_error (const Location, const char *fmt, ...) + RUST_ATTRIBUTE_GCC_DIAG (2, 3) + RUST_ATTRIBUTE_NORETURN; +extern void +rust_inform (const Location, const char *fmt, ...) + RUST_ATTRIBUTE_GCC_DIAG (2, 3); + +// rich locations +extern void +rust_error_at (const RichLocation &, const char *fmt, ...) + RUST_ATTRIBUTE_GCC_DIAG (2, 3); +// clang-format on + +// These interfaces provide a way for the front end to ask for +// the open/close quote characters it should use when formatting +// diagnostics (warnings, errors). +extern const char * +rust_open_quote (); +extern const char * +rust_close_quote (); + +// These interfaces are used by utilities above to pass warnings and +// errors (once format specifiers have been expanded) to the back end, +// and to determine quoting style. Avoid calling these routines directly; +// instead use the equivalent routines above. The back end is required to +// implement these routines. + +// clang-format off +extern void +rust_be_internal_error_at (const Location, const std::string &errmsg) + RUST_ATTRIBUTE_NORETURN; +extern void +rust_be_error_at (const Location, const std::string &errmsg); +extern void +rust_be_error_at (const RichLocation &, const std::string &errmsg); +extern void +rust_be_warning_at (const Location, int opt, const std::string &warningmsg); +extern void +rust_be_fatal_error (const Location, const std::string &errmsg) + RUST_ATTRIBUTE_NORETURN; +extern void +rust_be_inform (const Location, const std::string &infomsg); +extern void +rust_be_get_quotechars (const char **open_quote, const char **close_quote); +extern bool +rust_be_debug_p (void); +// clang-format on + +namespace Rust { +/* A structure used to represent an error. Useful for enabling + * errors to be ignored, e.g. if backtracking. */ +struct Error +{ + Location locus; + std::string message; + // TODO: store more stuff? e.g. node id? + + Error (Location locus, std::string message) + : locus (locus), message (std::move (message)) + { + message.shrink_to_fit (); + } + + // TODO: the attribute part might be incorrect + Error (Location locus, const char *fmt, + ...) /*RUST_ATTRIBUTE_GCC_DIAG (2, 3)*/ RUST_ATTRIBUTE_GCC_DIAG (3, 4); + + // Irreversibly emits the error as an error. + void emit_error () const { rust_error_at (locus, "%s", message.c_str ()); } + + // Irreversibly emits the error as a fatal error. + void emit_fatal_error () const + { + rust_fatal_error (locus, "%s", message.c_str ()); + } +}; +} // namespace Rust + +// rust_debug uses normal printf formatting, not GCC diagnostic formatting. +#define rust_debug(...) rust_debug_loc (Location (), __VA_ARGS__) + +// rust_sorry_at wraps GCC diagnostic "sorry_at" to accept "Location" instead of +// "location_t" +#define rust_sorry_at(location, ...) \ + sorry_at (location.gcc_location (), __VA_ARGS__) + +void +rust_debug_loc (const Location location, const char *fmt, + ...) ATTRIBUTE_PRINTF_2; + +#endif // !defined(RUST_DIAGNOSTICS_H) diff --git a/gcc/rust/rust-gcc-diagnostics.cc b/gcc/rust/rust-gcc-diagnostics.cc new file mode 100644 index 00000000000..db07372dfb5 --- /dev/null +++ b/gcc/rust/rust-gcc-diagnostics.cc @@ -0,0 +1,84 @@ +// 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 +// . + +// rust-gcc-diagnostics.cc -- GCC implementation of rust diagnostics interface. + +#include "rust-system.h" +#include "rust-diagnostics.h" + +#include "options.h" + +void +rust_be_internal_error_at (const Location location, const std::string &errmsg) +{ + std::string loc_str = Linemap::location_to_string (location); + if (loc_str.empty ()) + internal_error ("%s", errmsg.c_str ()); + else + internal_error ("at %s, %s", loc_str.c_str (), errmsg.c_str ()); +} + +void +rust_be_error_at (const Location location, const std::string &errmsg) +{ + location_t gcc_loc = location.gcc_location (); + error_at (gcc_loc, "%s", errmsg.c_str ()); +} + +void +rust_be_warning_at (const Location location, int opt, + const std::string &warningmsg) +{ + location_t gcc_loc = location.gcc_location (); + warning_at (gcc_loc, opt, "%s", warningmsg.c_str ()); +} + +void +rust_be_fatal_error (const Location location, const std::string &fatalmsg) +{ + location_t gcc_loc = location.gcc_location (); + fatal_error (gcc_loc, "%s", fatalmsg.c_str ()); +} + +void +rust_be_inform (const Location location, const std::string &infomsg) +{ + location_t gcc_loc = location.gcc_location (); + inform (gcc_loc, "%s", infomsg.c_str ()); +} + +void +rust_be_error_at (const RichLocation &location, const std::string &errmsg) +{ + /* TODO: 'error_at' would like a non-'const' 'rich_location *'. */ + rich_location &gcc_loc = const_cast (location.get ()); + error_at (&gcc_loc, "%s", errmsg.c_str ()); +} + +void +rust_be_get_quotechars (const char **open_qu, const char **close_qu) +{ + *open_qu = open_quote; + *close_qu = close_quote; +} + +bool +rust_be_debug_p (void) +{ + return !!flag_rust_debug; +} diff --git a/gcc/rust/rust-linemap.cc b/gcc/rust/rust-linemap.cc new file mode 100644 index 00000000000..b32a965a4aa --- /dev/null +++ b/gcc/rust/rust-linemap.cc @@ -0,0 +1,229 @@ +// 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 +// . + +// rust-linemap.cc -- GCC implementation of Linemap. + +#include "rust-linemap.h" + +// This class implements the Linemap interface defined by the +// frontend. + +class Gcc_linemap : public Linemap +{ +public: + Gcc_linemap () : Linemap (), in_file_ (false) {} + + void start_file (const char *file_name, unsigned int line_begin); + + void start_line (unsigned int line_number, unsigned int line_size); + + Location get_location (unsigned int column); + + void stop (); + + std::string to_string (Location); + + std::string location_file (Location); + + int location_line (Location); + + int location_column (Location); + +protected: + Location get_predeclared_location (); + + Location get_unknown_location (); + + bool is_predeclared (Location); + + bool is_unknown (Location); + +private: + // Whether we are currently reading a file. + bool in_file_; +}; + +Linemap *Linemap::instance_ = NULL; + +// Start getting locations from a new file. + +void +Gcc_linemap::start_file (const char *file_name, unsigned line_begin) +{ + if (this->in_file_) + linemap_add (line_table, LC_LEAVE, 0, NULL, 0); + linemap_add (line_table, LC_ENTER, 0, file_name, line_begin); + this->in_file_ = true; +} + +// Stringify a location + +std::string +Gcc_linemap::to_string (Location location) +{ + const line_map_ordinary *lmo; + location_t resolved_location; + + // Screen out unknown and predeclared locations; produce output + // only for simple file:line locations. + resolved_location + = linemap_resolve_location (line_table, location.gcc_location (), + LRK_SPELLING_LOCATION, &lmo); + if (lmo == NULL || resolved_location < RESERVED_LOCATION_COUNT) + return ""; + const char *path = LINEMAP_FILE (lmo); + if (!path) + return ""; + + // Strip the source file down to the base file, to reduce clutter. + std::stringstream ss; + ss << lbasename (path) << ":" << SOURCE_LINE (lmo, location.gcc_location ()) + << ":" << SOURCE_COLUMN (lmo, location.gcc_location ()); + return ss.str (); +} + +// Return the file name for a given location. + +std::string +Gcc_linemap::location_file (Location loc) +{ + return LOCATION_FILE (loc.gcc_location ()); +} + +// Return the line number for a given location. + +int +Gcc_linemap::location_line (Location loc) +{ + return LOCATION_LINE (loc.gcc_location ()); +} + +// Return the column number for a given location. +int +Gcc_linemap::location_column (Location loc) +{ + return LOCATION_COLUMN (loc.gcc_location ()); +} + +// Stop getting locations. + +void +Gcc_linemap::stop () +{ + linemap_add (line_table, LC_LEAVE, 0, NULL, 0); + this->in_file_ = false; +} + +// Start a new line. + +void +Gcc_linemap::start_line (unsigned lineno, unsigned linesize) +{ + linemap_line_start (line_table, lineno, linesize); +} + +// Get a location. + +Location +Gcc_linemap::get_location (unsigned column) +{ + return Location (linemap_position_for_column (line_table, column)); +} + +// Get the unknown location. + +Location +Gcc_linemap::get_unknown_location () +{ + return Location (UNKNOWN_LOCATION); +} + +// Get the predeclared location. + +Location +Gcc_linemap::get_predeclared_location () +{ + return Location (BUILTINS_LOCATION); +} + +// Return whether a location is the predeclared location. + +bool +Gcc_linemap::is_predeclared (Location loc) +{ + return loc.gcc_location () == BUILTINS_LOCATION; +} + +// Return whether a location is the unknown location. + +bool +Gcc_linemap::is_unknown (Location loc) +{ + return loc.gcc_location () == UNKNOWN_LOCATION; +} + +// Return the Linemap to use for the gcc backend. + +Linemap * +rust_get_linemap () +{ + return new Gcc_linemap; +} + +RichLocation::RichLocation (Location root) + : gcc_rich_loc (line_table, root.gcc_location ()) +{ + /*rich_location (line_maps *set, location_t loc, + const range_label *label = NULL);*/ +} + +RichLocation::~RichLocation () {} + +void +RichLocation::add_range (Location loc) +{ + gcc_rich_loc.add_range (loc.gcc_location ()); +} + +void +RichLocation::add_fixit_insert_before (const std::string &new_parent) +{ + gcc_rich_loc.add_fixit_insert_before (new_parent.c_str ()); +} + +void +RichLocation::add_fixit_insert_before (Location where, + const std::string &new_parent) +{ + gcc_rich_loc.add_fixit_insert_before (where.gcc_location (), + new_parent.c_str ()); +} + +void +RichLocation::add_fixit_insert_after (const std::string &new_parent) +{ + gcc_rich_loc.add_fixit_insert_after (new_parent.c_str ()); +} + +void +RichLocation::add_fixit_insert_after (Location where, + const std::string &new_parent) +{ + gcc_rich_loc.add_fixit_insert_after (where.gcc_location (), + new_parent.c_str ()); +} diff --git a/gcc/rust/rust-linemap.h b/gcc/rust/rust-linemap.h new file mode 100644 index 00000000000..0ba95f87575 --- /dev/null +++ b/gcc/rust/rust-linemap.h @@ -0,0 +1,163 @@ +// rust-linemap.h -- interface to location tracking -*- C++ -*- + +// Copyright 2011 The Go Authors. All rights reserved. +// Copyright (C) 2020-2022 Free Software Foundation, Inc. + +// Use of this source code is governed by a BSD-style +// license that can be found in the '../go/gofrontend/LICENSE' file. + +#ifndef RUST_LINEMAP_H +#define RUST_LINEMAP_H + +#include "rust-system.h" + +// The backend must define a type named Location which holds +// information about a location in a source file. The only thing the +// frontend does with instances of Location is pass them back to the +// backend interface. The Location type must be assignable, and it +// must be comparable: i.e., it must support operator= and operator<. +// The type is normally passed by value rather than by reference, and +// it should support that efficiently. The type should be defined in +// "rust-location.h". +#include "rust-location.h" + +// The Linemap class is a pure abstract interface, plus some static +// convenience functions. The backend must implement the interface. + +/* TODO: probably better to replace linemap implementation as pure abstract + * interface with some sort of compile-time switch (macros or maybe templates if + * doable without too much extra annoyance) as to the definition of the methods + * or whatever. This is to improve performance, as virtual function calls would + * otherwise have to be made in tight loops like in the lexer. */ + +class Linemap +{ +public: + Linemap () + { + // Only one instance of Linemap is allowed to exist. + rust_assert (Linemap::instance_ == NULL); + Linemap::instance_ = this; + } + + virtual ~Linemap () { Linemap::instance_ = NULL; } + + // Subsequent Location values will come from the file named + // FILE_NAME, starting at LINE_BEGIN. Normally LINE_BEGIN will be + // 0, but it will be non-zero if the Rust source has a //line comment. + virtual void start_file (const char *file_name, unsigned int line_begin) = 0; + + // Subsequent Location values will come from the line LINE_NUMBER, + // in the current file. LINE_SIZE is the size of the line in bytes. + // This will normally be called for every line in a source file. + virtual void start_line (unsigned int line_number, unsigned int line_size) + = 0; + + // Get a Location representing column position COLUMN on the current + // line in the current file. + virtual Location get_location (unsigned int column) = 0; + + // Stop generating Location values. This will be called after all + // input files have been read, in case any cleanup is required. + virtual void stop () = 0; + + // Produce a human-readable description of a Location, e.g. + // "foo.rust:10". Returns an empty string for predeclared, builtin or + // unknown locations. + virtual std::string to_string (Location) = 0; + + // Return the file name for a given location. + virtual std::string location_file (Location) = 0; + + // Return the line number for a given location. + virtual int location_line (Location) = 0; + + // Return the column number for a given location. + virtual int location_column (Location) = 0; + +protected: + // Return a special Location used for predeclared identifiers. This + // Location should be different from that for any actual source + // file. This location will be used for various different types, + // functions, and objects created by the frontend. + virtual Location get_predeclared_location () = 0; + + // Return a special Location which indicates that no actual location + // is known. This is used for undefined objects and for errors. + virtual Location get_unknown_location () = 0; + + // Return whether the argument is the Location returned by + // get_predeclared_location. + virtual bool is_predeclared (Location) = 0; + + // Return whether the argument is the Location returned by + // get_unknown_location. + virtual bool is_unknown (Location) = 0; + + // The single existing instance of Linemap. + static Linemap *instance_; + +public: + // Following are convenience static functions, which allow us to + // access some virtual functions without explicitly passing around + // an instance of Linemap. + + // Return the special Location used for predeclared identifiers. + static Location predeclared_location () + { + rust_assert (Linemap::instance_ != NULL); + return Linemap::instance_->get_predeclared_location (); + } + + // Return the special Location used when no location is known. + static Location unknown_location () + { + rust_assert (Linemap::instance_ != NULL); + return Linemap::instance_->get_unknown_location (); + } + + // Return whether the argument is the special location used for + // predeclared identifiers. + static bool is_predeclared_location (Location loc) + { + rust_assert (Linemap::instance_ != NULL); + return Linemap::instance_->is_predeclared (loc); + } + + // Return whether the argument is the special location used when no + // location is known. + static bool is_unknown_location (Location loc) + { + rust_assert (Linemap::instance_ != NULL); + return Linemap::instance_->is_unknown (loc); + } + + // Produce a human-readable description of a Location. + static std::string location_to_string (Location loc) + { + rust_assert (Linemap::instance_ != NULL); + return Linemap::instance_->to_string (loc); + } + + // Return the file name of a location. + static std::string location_to_file (Location loc) + { + rust_assert (Linemap::instance_ != NULL); + return Linemap::instance_->location_file (loc); + } + + // Return line number of a location. + static int location_to_line (Location loc) + { + rust_assert (Linemap::instance_ != NULL); + return Linemap::instance_->location_line (loc); + } + + static int location_to_column (Location loc) + { + rust_assert (Linemap::instance_ != NULL); + return Linemap::instance_->location_column (loc); + } +}; + +#endif // !defined(RUST_LINEMAP_H) diff --git a/gcc/rust/rust-location.h b/gcc/rust/rust-location.h new file mode 100644 index 00000000000..1bb875fe6a4 --- /dev/null +++ b/gcc/rust/rust-location.h @@ -0,0 +1,105 @@ +// 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 +// . + +// rust-location.h -- GCC specific Location declaration. -*- C++ -*- + +#ifndef RUST_LOCATION_H +#define RUST_LOCATION_H + +#include "rust-system.h" + +// A location in an input source file. + +class Location +{ +public: + Location () : gcc_loc_ (UNKNOWN_LOCATION) {} + + explicit Location (location_t loc) : gcc_loc_ (loc) {} + + location_t gcc_location () const { return gcc_loc_; } + + Location operator+= (location_t rhs) + { + gcc_loc_ += rhs; + return *this; + } + + Location operator-= (location_t rhs) + { + gcc_loc_ -= rhs; + return *this; + } + + bool operator== (location_t rhs) { return rhs == gcc_loc_; } + +private: + location_t gcc_loc_; +}; + +// The Rust frontend requires the ability to compare Locations. + +inline bool +operator< (Location loca, Location locb) +{ + return loca.gcc_location () < locb.gcc_location (); +} + +inline bool +operator== (Location loca, Location locb) +{ + return loca.gcc_location () == locb.gcc_location (); +} + +inline Location +operator+ (Location lhs, location_t rhs) +{ + lhs += rhs; + return lhs; +} + +inline Location +operator- (Location lhs, location_t rhs) +{ + lhs -= rhs; + return lhs; +} + +class RichLocation +{ +public: + RichLocation (Location root); + ~RichLocation (); + + void add_range (Location loc); + + void add_fixit_insert_before (const std::string &new_parent); + + void add_fixit_insert_before (Location where, const std::string &new_parent); + + void add_fixit_insert_after (const std::string &new_parent); + + void add_fixit_insert_after (Location where, const std::string &new_parent); + + const rich_location &get () const { return gcc_rich_loc; } + +private: + rich_location gcc_rich_loc; +}; + +#endif // !defined(RUST_LOCATION_H) diff --git a/gcc/rust/rust-system.h b/gcc/rust/rust-system.h new file mode 100644 index 00000000000..3a600237966 --- /dev/null +++ b/gcc/rust/rust-system.h @@ -0,0 +1,86 @@ +// rust-system.h -- Rust frontend inclusion of gcc header files -*- C++ -*- +// 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 +// . + +#ifndef RUST_SYSTEM_H +#define RUST_SYSTEM_H + +#define INCLUDE_ALGORITHM +#include "config.h" + +/* Define this so that inttypes.h defines the PRI?64 macros even + when compiling with a C++ compiler. Define it here so in the + event inttypes.h gets pulled in by another header it is already + defined. */ +#define __STDC_FORMAT_MACROS + +// These must be included before the #poison declarations in system.h. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Rust frontend requires C++11 minimum, so will have unordered_map and set +#include +#include + +/* We don't really need iostream, but some versions of gmp.h include + * it when compiled with C++, which means that we need to include it + * before the macro magic of safe-ctype.h, which is included by + * system.h. */ +#include + +#include "system.h" +#include "ansidecl.h" +#include "coretypes.h" + +#include "diagnostic-core.h" /* For error_at and friends. */ +#include "intl.h" /* For _(). */ + +#define RUST_ATTRIBUTE_NORETURN ATTRIBUTE_NORETURN + +// File separator to use based on whether or not the OS we're working with is +// DOS-based +#if defined(HAVE_DOS_BASED_FILE_SYSTEM) +constexpr static const char *file_separator = "\\"; +#else +constexpr static const char *file_separator = "/"; +#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ + +// When using gcc, rust_assert is just gcc_assert. +#define rust_assert(EXPR) gcc_assert (EXPR) + +// When using gcc, rust_unreachable is just gcc_unreachable. +#define rust_unreachable() gcc_unreachable () + +extern void +rust_preserve_from_gc (tree t); + +extern const char * +rust_localize_identifier (const char *ident); + +#endif // !defined(RUST_SYSTEM_H) From patchwork Wed Aug 24 11:59:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 57006 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 8E9EE3918A70 for ; Wed, 24 Aug 2022 12:08:09 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com [IPv6:2a00:1450:4864:20::42e]) by sourceware.org (Postfix) with ESMTPS id E50C43850865; Wed, 24 Aug 2022 12:01:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org E50C43850865 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x42e.google.com with SMTP id h5so19679262wru.7; Wed, 24 Aug 2022 05:01:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=lXB+tjnWVg4//z7kvF/7IWAgJLIgF2PF9Pq5HkfPOo8=; b=deXgyRZ8TORaQIornxLzVMtzIcz6cULYFziuYRjprDjoa0IWrKBPBOZ2UY3AVIt1Qk BAZPTYJSwmz10qheTsXmp+eh/ozP13tc3zZ2YnVEuoCcVH/8dTMaQj7PR27aD95zbWc3 33W9Qi7oXX+SCf6Tv9x7QvD8bp+MlvkNx6pogvZJWoQhPZYrvcf2fgashILFNdzO60YJ lfGgfm1cALBfe12EZwB+D7OJJrvPdFvyPF279scV8Ta+G5i4RPNg5fL0z4kNCFUxmX32 E5cE8Toy0YvSfFbSBx1KcxaJJ/t6R2HidmCKq8KwAWrQBL3zjoo6XbZo9kpdniZOsljE aQNA== 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; bh=lXB+tjnWVg4//z7kvF/7IWAgJLIgF2PF9Pq5HkfPOo8=; b=xHna7jDmI12k2LHZdxQshV4015t2fsZMh+hzx9DCGpmF3ZD2wQ3YGo9I3X228YjJnZ O2ioTDxSx6bia0A8KNQmjnNr0G9p1U9oBXtVw6srpA1NeahGBLwd3M5IsHcUK98mjFmT rkIO24S7+DMeUUXQJ3MFoOA7FtfQrIzDL7mmOzSiPFzn3hwo4ug5WrZ1pZ2hUAValrRk 5Tzu5YbqYG/4ByXxLq8N5DysqXMeGdDA6RUpQzLT5XI/jLuITVkdJGI3JQWD9G1zXo3u QEWU+RqsDMO6EkOEEdrP7tTNOlpkqMBqk6nVDq+UPvea/qr8OtcUWD1/aYr8SOQSEukw oxAQ== X-Gm-Message-State: ACgBeo3nBMQj8jQNgD8MQ1mFZpb3V4/yeOk+o9twQmFJdxvVWTaR4hc+ cNbFISJCTDF0ZkwCNRp+k7+1npUCB9E= X-Google-Smtp-Source: AA6agR7Abq6dyYaPZ+EixXvk33RX7nrelZJ6mPgOHUUVUzR7xqN91CWB6ygEh1LB8TT+v1MvWF+3Xg== X-Received: by 2002:a5d:43c2:0:b0:225:2d8a:ad25 with SMTP id v2-20020a5d43c2000000b002252d8aad25mr15760365wrr.208.1661342477057; Wed, 24 Aug 2022 05:01:17 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.01.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:01:15 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 31/37] gccrs: Add GCC Rust front-end Make-lang.in Date: Wed, 24 Aug 2022 12:59:50 +0100 Message-Id: <20220824115956.737931-32-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-12.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron This is the Makefile for our front-end. --- gcc/rust/Make-lang.in | 400 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 400 insertions(+) create mode 100644 gcc/rust/Make-lang.in diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in new file mode 100644 index 00000000000..f687cc2f667 --- /dev/null +++ b/gcc/rust/Make-lang.in @@ -0,0 +1,400 @@ +# Make-lang.in -- Top level -*- makefile -*- fragment for GCC 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 +# . + +# This file provides the language dependent support in the main Makefile. + +#RUST_EXES = rust + +# Use strict warnings for this front end. +rust-warn = $(STRICT_WARN) + +# Installation name. Useful for cross compilers and used during install. +GCCRS_INSTALL_NAME := $(shell echo gccrs|sed '$(program_transform_name)') +GCCRS_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo gccrs|sed '$(program_transform_name)') + +# Define the names for selecting rust in LANGUAGES. +rust: rust1$(exeext) + +# Tell GNU make to ignore files by these names if they exist. +.PHONY: rust + +# removed GRS_CFLAGS from here + +CFLAGS-rust/rustspec.o += $(DRIVER_DEFINES) + +# Create the compiler driver gccrs. +# A compiler driver is the program that interprets command argument and can be called from the command +# line - e.g. gcc or g++, and not cc1, which is the actual compiler + +# Create driver objects +GCCRS_D_OBJS = \ + $(GCC_OBJS) \ + rust/rustspec.o \ + $(END) + +gccrs$(exeext): $(GCCRS_D_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS) + +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \ + $(GCCRS_D_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a \ + $(EXTRA_GCC_LIBS) $(LIBS) + +# List of host object files used by the rust language - files for translation from the parse tree +# to GENERIC +# The compiler proper, not driver +GRS_OBJS = \ + rust/rust-lang.o \ + rust/rust-object-export.o \ + rust/rust-linemap.o \ + rust/rust-gcc-diagnostics.o \ + rust/rust-diagnostics.o \ + rust/rust-gcc.o \ + rust/rust-token.o \ + rust/rust-lex.o \ + rust/rust-cfg-parser.o \ + rust/rust-parse.o \ + rust/rust-ast-full-test.o \ + rust/rust-ast-dump.o \ + rust/rust-hir-dump.o \ + rust/rust-session-manager.o \ + rust/rust-compile.o \ + rust/rust-mangle.o \ + rust/rust-compile-resolve-path.o \ + rust/rust-macro-expand.o \ + rust/rust-attribute-visitor.o \ + rust/rust-macro-invoc-lexer.o \ + rust/rust-macro-substitute-ctx.o \ + rust/rust-macro-builtins.o \ + rust/rust-hir-full-test.o \ + rust/rust-hir-map.o \ + rust/rust-attributes.o \ + rust/rust-abi.o \ + rust/rust-ast-lower.o \ + rust/rust-ast-lower-base.o \ + rust/rust-ast-lower-pattern.o \ + rust/rust-ast-lower-item.o \ + rust/rust-name-resolver.o \ + rust/rust-ast-resolve.o \ + rust/rust-ast-resolve-base.o \ + rust/rust-ast-resolve-item.o \ + rust/rust-ast-resolve-pattern.o \ + rust/rust-ast-resolve-expr.o \ + rust/rust-ast-resolve-type.o \ + rust/rust-ast-resolve-path.o \ + rust/rust-ast-resolve-stmt.o \ + rust/rust-ast-resolve-struct-expr-field.o \ + rust/rust-hir-type-check.o \ + rust/rust-privacy-check.o \ + rust/rust-privacy-ctx.o \ + rust/rust-reachability.o \ + rust/rust-visibility-resolver.o \ + rust/rust-pub-restricted-visitor.o \ + rust/rust-privacy-reporter.o \ + rust/rust-tyty.o \ + rust/rust-tyty-call.o \ + rust/rust-tyctx.o \ + rust/rust-tyty-bounds.o \ + rust/rust-hir-type-check-util.o \ + rust/rust-hir-trait-resolve.o \ + rust/rust-hir-type-check-toplevel.o \ + rust/rust-hir-type-check-item.o \ + rust/rust-hir-type-check-type.o \ + rust/rust-hir-type-check-struct.o \ + rust/rust-hir-type-check-pattern.o \ + rust/rust-hir-type-check-expr.o \ + rust/rust-hir-type-check-stmt.o \ + rust/rust-hir-type-check-enumitem.o \ + rust/rust-hir-type-check-implitem.o \ + rust/rust-hir-dot-operator.o \ + rust/rust-coercion.o \ + rust/rust-casts.o \ + rust/rust-hir-type-check-base.o \ + rust/rust-autoderef.o \ + rust/rust-substitution-mapper.o \ + rust/rust-const-checker.o \ + rust/rust-lint-marklive.o \ + rust/rust-lint-unused-var.o \ + rust/rust-hir-type-check-path.o \ + rust/rust-unsafe-checker.o \ + rust/rust-compile-intrinsic.o \ + rust/rust-compile-pattern.o \ + rust/rust-compile-fnparam.o \ + rust/rust-base62.o \ + rust/rust-optional-test.o \ + rust/rust-compile-item.o \ + rust/rust-compile-implitem.o \ + rust/rust-compile-stmt.o \ + rust/rust-compile-expr.o \ + rust/rust-compile-type.o \ + rust/rust-compile-block.o \ + rust/rust-compile-struct-field-expr.o \ + rust/rust-constexpr.o \ + rust/rust-compile-base.o \ + rust/rust-tree.o \ + rust/rust-compile-context.o \ + rust/rust-export-metadata.o \ + rust/rust-imports.o \ + rust/rust-import-archive.o \ + rust/rust-extern-crate.o \ + $(END) +# removed object files from here + +# All language-specific object files for Rust. +RUST_ALL_OBJS = $(GRS_OBJS) $(RUST_TARGET_OBJS) + +rust_OBJS = $(RUST_ALL_OBJS) rust/rustspec.o + +# The compiler itself is called rust1 (formerly grs1) +rust1$(exeext): $(RUST_ALL_OBJS) attribs.o $(BACKEND) $(LIBDEPS) + +$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \ + $(RUST_ALL_OBJS) attribs.o $(BACKEND) $(LIBS) $(BACKENDLIBS) + +# Build hooks. + +lang_checks += check-rust +lang_checks_parallelized += check-rust +check_rust_parallelize = 10 + +# Copies its dependencies into the source directory. This generally should be used for generated files +# such as Bison output files which are not version-controlled, but should be included in any release +# tarballs. This target will be executed during a bootstrap if ‘--enable-generated-files-in-srcdir’ +# was specified as a configure option. +rust.srcextra: + +rust.all.cross: gccrs$(exeext) + +# idk what this does but someone used it +rust.start.encap: gccrs$(exeext) +rust.rest.encap: + +# Build generated man pages for the front end from Texinfo manuals (see Man Page Generation), in the +# build directory. This target is only called if the necessary tools are available, but should ignore +# errors so as not to stop the build if errors occur; man pages are optional and the tools involved +# may be installed in a broken way. +rust.man: + +# Copies its dependencies into the source directory. These targets will be executed during a bootstrap +# if ‘--enable-generated-files-in-srcdir’ was specified as a configure option. +rust.srcman: + +# Clean hooks. + +rust.mostlyclean: +# cd $(srcdir)/rust; rm -f *.o y.tab.h y.tab.c lex.yy.c + +rust.clean: rust.mostlyclean + +# Builds an etags TAGS file in the language subdirectory in the source tree. +# TODO: add more directories if I add more +rust.tags: force + cd $(srcdir)/rust; \ + etags -o TAGS.sub *.y *.l *.cc *.h ast/*.h ast/*.cc lex/*.h lex/*.cc parse/*.h parse/*.cc; \ + etags --include TAGS.sub --include ../TAGS.sub + +# Build documentation hooks. + +# Build info documentation for the front end, in the build directory. This target is only called by +# ‘make bootstrap’ if a suitable version of makeinfo is available, so does not need to check for this, +# and should fail if an error occurs. +rust.info: + +rust.srcinfo: + +# Build DVI documentation for the front end, in the build directory. This should be done using +# $(TEXI2DVI), with appropriate -I arguments pointing to directories of included files. +rust.dvi: + +# Build PDF documentation for the front end, in the build directory. This should be done using +# $(TEXI2PDF), with appropriate -I arguments pointing to directories of included files. +rust.pdf: + +doc/rust.info: +doc/rust.dvi: +doc/rust.pdf: + +# Build HTML documentation for the front end, in the build directory. +rust.html: + +# Install hooks. + +# Install everything that is part of the front end, apart from the compiler executables listed in +# compilers in config-lang.in. +rust.install-common: installdirs +# -rm -f $(DESTDIR)$(bindir)/$(GCCRS_INSTALL_NAME)$(exeext) +# -rm -f $(DESTDIR)$(bindir)/$(GCCRS_TARGET_INSTALL_NAME)$(exeext) +# $(INSTALL_PROGRAM) gccrs$(exeext) $(DESTDIR)$(bindir)/$(GCCRS_INSTALL_NAME)$(exeext) +# if test -f $(DESTDIR)$(bindir)$(GCCRS_TARGET_INSTALL_NAME)$(exeext); then \ +# :; \ +# else \ +# cd $(DESTDIR)$(bindir) && \ +# $(LN) $(GCCRS_INSTALL_NAME)$(exeext) $(GCCRS_TARGET_INSTALL_NAME)$(exeext); \ +# fi + -rm -f $(DESTDIR)$(bindir)/$(GCCRS_INSTALL_NAME)$(exeext) + $(INSTALL_PROGRAM) gccrs$(exeext) $(DESTDIR)$(bindir)/$(GCCRS_INSTALL_NAME)$(exeext) + rm -f $(DESTDIR)$(bindir)/$(GCCRS_TARGET_INSTALL_NAME)$(exeext); \ + ( cd $(DESTDIR)$(bindir) && \ + $(LN) $(GCCRS_INSTALL_NAME)$(exeext) $(GCCRS_TARGET_INSTALL_NAME)$(exeext) ); \ + +# Install headers needed for plugins. +rust.install-plugin: + +# Uninstall files installed by installing the compiler. This is currently documented not to be +# supported, so the hook need not do anything. +rust.uninstall: +# -rm -rf $(DESTDIR)/$(bindir)/$(GCCRS_INSTALL_NAME)$(exeext) + -rm -f gccrs$(exeext) grs1$(exeext) + -rm -f $(RUST_ALL_OBJS) +# ^those two are a maybe + +# Enable selftests for the rust frontend +selftest-rust: s-selftest-rust + +RUST_SELFTEST_FLAGS = -xrs $(SELFTEST_FLAGS) +RUST_SELFTEST_DEPS = rust1$(exeext) $(SELFTEST_DEPS) + +# Run the rust selftests +s-selftest-rust: $(RUST_SELFTEST_DEPS) + $(GCC_FOR_TARGET) $(RUST_SELFTEST_FLAGS) + $(STAMP) $@ + +# Install info documentation for the front end, if it is present in the source directory. This target +# should have dependencies on info files that should be installed. +rust.install-info: + +rust.install-pdf: + +# Install man pages for the front end. This target should ignore errors. +rust.install-man: + +# Stage hooks: +# The toplevel makefile has already created stage?/rust at this point. +# Used for handling bootstrap + +rust.stage1: stage1-start + -mv rust/*$(objext) stage1/rust +rust.stage2: stage2-start + -mv rust/*$(objext) stage2/rust +rust.stage3: stage3-start + -mv rust/*$(objext) stage3/rust +rust.stage4: stage4-start + -mv rust/*$(objext) stage4/rust +rust.stageprofile: stageprofile-start + -mv rust/*$(objext) stageprofile/rust +rust.stagefeedback: stagefeedback-start + -mv rust/*$(objext) stagefeedback/rust + +CFLAGS-rust/rust-lang.o += -DDEFAULT_TARGET_VERSION=\"$(version)\" \ + -DDEFAULT_TARGET_MACHINE=\"$(target_noncanonical)\" + +# cross-folder includes - add new folders later +RUST_INCLUDES = -I $(srcdir)/rust \ + -I $(srcdir)/rust/lex \ + -I $(srcdir)/rust/parse \ + -I $(srcdir)/rust/ast \ + -I $(srcdir)/rust/analysis \ + -I $(srcdir)/rust/backend \ + -I $(srcdir)/rust/expand \ + -I $(srcdir)/rust/hir/tree \ + -I $(srcdir)/rust/hir \ + -I $(srcdir)/rust/resolve \ + -I $(srcdir)/rust/util \ + -I $(srcdir)/rust/typecheck \ + -I $(srcdir)/rust/checks/lints \ + -I $(srcdir)/rust/checks/errors \ + -I $(srcdir)/rust/checks/errors/privacy \ + -I $(srcdir)/rust/util \ + -I $(srcdir)/rust/metadata + +# add files that require cross-folder includes - currently rust-lang.o, rust-lex.o +CFLAGS-rust/rust-lang.o += $(RUST_INCLUDES) +CFLAGS-rust/rust-lex.o += $(RUST_INCLUDES) +CFLAGS-rust/rust-parse.o += $(RUST_INCLUDES) +CFLAGS-rust/rust-session-manager.o += $(RUST_INCLUDES) + +# TODO: possibly find a way to ensure C++11 compilation level here? +RUST_CXXFLAGS = -std=c++11 -Wno-unused-parameter -Werror=overloaded-virtual + +# build all rust/lex files in rust folder, add cross-folder includes +rust/%.o: rust/lex/%.cc + $(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $< + $(POSTCOMPILE) + +# build all rust/parse files in rust folder, add cross-folder includes +rust/%.o: rust/parse/%.cc + $(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $< + $(POSTCOMPILE) + +# build rust/ast files in rust folder +rust/%.o: rust/ast/%.cc + $(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $< + $(POSTCOMPILE) + +# build rust/backend files in rust folder +rust/%.o: rust/backend/%.cc + $(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $< + $(POSTCOMPILE) + +# build rust/expand files in rust folder +rust/%.o: rust/expand/%.cc + $(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $< + $(POSTCOMPILE) + +# build rust/util files in rust folder +rust/%.o: rust/util/%.cc + $(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $< + $(POSTCOMPILE) + +# build rust/hir files in rust folder +rust/%.o: rust/hir/%.cc + $(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $< + $(POSTCOMPILE) + +# build rust/hir/tree files in rust folder +rust/%.o: rust/hir/tree/%.cc + $(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $< + $(POSTCOMPILE) + +# build rust/resolve files in rust folder +rust/%.o: rust/resolve/%.cc + $(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $< + $(POSTCOMPILE) + +# build rust/typecheck files in rust folder +rust/%.o: rust/typecheck/%.cc + $(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $< + $(POSTCOMPILE) + +# build rust/checks/lints files in rust folder +rust/%.o: rust/checks/lints/%.cc + $(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $< + $(POSTCOMPILE) + +# build rust/checks/errors files in rust folder +rust/%.o: rust/checks/errors/%.cc + $(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $< + $(POSTCOMPILE) + +# build privacy pass files in rust folder +rust/%.o: rust/checks/errors/privacy/%.cc + $(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $< + $(POSTCOMPILE) + +# build rust/metadata files in rust folder +rust/%.o: rust/metadata/%.cc + $(COMPILE) $(RUST_CXXFLAGS) $(RUST_INCLUDES) $< + $(POSTCOMPILE) From patchwork Wed Aug 24 11:59:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 57002 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 131F838286E2 for ; Wed, 24 Aug 2022 12:07:28 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x330.google.com (mail-wm1-x330.google.com [IPv6:2a00:1450:4864:20::330]) by sourceware.org (Postfix) with ESMTPS id CDF41385116E; Wed, 24 Aug 2022 12:01:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org CDF41385116E Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wm1-x330.google.com with SMTP id c187-20020a1c35c4000000b003a30d88fe8eso789509wma.2; Wed, 24 Aug 2022 05:01:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=QKeiBINY1vFvxx75xu0Zr9m91z9d0MWOyZj/8MtaNps=; b=YN5sPf90AqoKwXHk89c7AHSNL9p33LNejAUmiX4u2SmTlQh83jdEpgW5t1eOG/rffI JUhDWvOpgcLgcgsthkCn/WOnbySoTWQ6nbtyp7mm+Jpob/il7dYpVSaqag/9c8D04lRy uJUUE2tuVpzGy0SxnKVOQwhXc8p6Ib2vFf1Q9otB3bS+xZU6Gud1adGnCKgkhPBqmo0a ldDjYU6CnGPP1YP+vVAgoMSbWCx57VL0b5zVK10916cadySTMY+ruFgH0SI8UYK1opDQ qcE2tFjbjScZlkNSiSaaTWp7KhFK0eCIEOHmEkyCHlQfEvS8gNb9OOlcLBsBlcYYqAf8 VfDQ== 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; bh=QKeiBINY1vFvxx75xu0Zr9m91z9d0MWOyZj/8MtaNps=; b=Dgfxwrzn2eHwbNkzLfC7ysFqHrlk6Cir35P5OcPe4INk+N0VtCR2VaxfWDU2me0K/m iJSdVCtrG1yfHSx/BMnXct/6D0vekdlBzEs3lLN8w9pAwZeGvadE+R/OZ2jbDa5ybYb/ 6JSyAnjnSKnkZcbH9HKI3zXHe+LN7/1Y0S9zQbrLO3ZKJ9FE+8JQnfHvUu/rDXxWizzw 4OJTLgtaiEIhKJ3ZLMZaTpqrrxOHlCvPkKexlr4U3AFEFMSe6EKPre8GKXR7KaWSWfel RARqbmHL3nBD+FUj1p74D/VbXYVbqZsFaKliuGOtJ4Mp2WBrUxkyGRhZ+P6eP89g92gA rdZg== X-Gm-Message-State: ACgBeo1Oc7x+zXLoqJLT8SCN8RDuJW06cIihtWnAhbtPzYmGU9lEPZxj sUsQwMCXQSQ3Xb4wenaK7UCwgscE0F8= X-Google-Smtp-Source: AA6agR6U/Dh0BCUBmmdD9/9twwgCSHKJY6ZSeqGR+XwsP/HFGv1gVTTZIC/1pcrWNfcJFys8ptYEfw== X-Received: by 2002:a05:600c:2059:b0:3a5:92cc:19c5 with SMTP id p25-20020a05600c205900b003a592cc19c5mr4793186wmg.101.1661342478479; Wed, 24 Aug 2022 05:01:18 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.01.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:01:17 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 32/37] gccrs: Add config-lang.in Date: Wed, 24 Aug 2022 12:59:51 +0100 Message-Id: <20220824115956.737931-33-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron This was a copy paste from gccgo front-end, we do not use any of the target_libs yet but we will need these when we support the libpanic crate. --- gcc/rust/config-lang.in | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 gcc/rust/config-lang.in diff --git a/gcc/rust/config-lang.in b/gcc/rust/config-lang.in new file mode 100644 index 00000000000..d2ff376032a --- /dev/null +++ b/gcc/rust/config-lang.in @@ -0,0 +1,34 @@ +# config-lang.in -- Top level configure fragment for gcc 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 +# . + +# Configure looks for the existence of this file to auto-config each language. +# We define several parameters used by configure: +# +# language - name of language as it would appear in $(LANGUAGES) +# compilers - value to add to $(COMPILERS) + +language="rust" +compilers="rust1\$(exeext)" + +build_by_default="no" + +target_libs="target-libffi target-libbacktrace" + +gtfiles="\$(srcdir)/rust/rust-lang.cc" From patchwork Wed Aug 24 11:59:52 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 57003 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 9962E3835E25 for ; Wed, 24 Aug 2022 12:07:35 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x436.google.com (mail-wr1-x436.google.com [IPv6:2a00:1450:4864:20::436]) by sourceware.org (Postfix) with ESMTPS id 44E6B393BA5E; Wed, 24 Aug 2022 12:01:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 44E6B393BA5E Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x436.google.com with SMTP id z16so1691801wrh.10; Wed, 24 Aug 2022 05:01:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=PLHaFofDCBIcsZEJ2vDNrxPPfrseoaLObVA5Vu3MuoM=; b=A85rN9LTvfGjlx2drSlpAiVfwAZrZ+6S8bEilfWRvDrYiUKgehJ2qGgxmCzbgUR9jU rqIhPC5V7GlQJkfulj1LTy+JD7ljlChXfLg+WqKV1osQpoD9MHJSmy0le9Tc932kwgs8 MIcKryS7ya6dDYLrG6+Hz7htt4ZotC3kYm7L3pBUbDKZhMFctx+OA4ID6bl4GVM/C1D2 zAdh0tFc7gF2EGeutJOcBpU9pLKAzBcUAjVni5Cre+wR+1d7/N6EcJ+voCYmOhzU9Shg uUS5HH+MTfq2YcFgg8ZDdZIuZ5pBR+4lWlFOnR/cCOwE20cm5Ma/JPyIl/AYlfYOcisQ KZ/g== 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; bh=PLHaFofDCBIcsZEJ2vDNrxPPfrseoaLObVA5Vu3MuoM=; b=ICi+tqB9S0LpDYqsEU8YDnTtKtVT5vKBayh7bk9HsNwB6BQaBYxJFJCyfzKTIG6Zo1 AEM5dxYC2edYkXbn9BK6E5DFuu12RL75S2trPIS/zr+Jf4t7qrO+ScFOQleoHpFs0RSL QI1H4EOcQt+1yi+oHQr5+34g5z9RC1vV3bEMSzKmVIzb6FnudBXpDaiiWoothq13z9fm IJq8WFeEMiS4Yr9HiriZemcxkhMGwYHG12w0dhRBtigg+Qj9ZYjbVRzOAthiPpLAurH2 o9V/L3zekcw7zmZwV9Xxoxwl+T448LiHaMGCTPF/Zom2y+tAF7qh7zNTelPD7bTY1vY+ qPUQ== X-Gm-Message-State: ACgBeo0W9p+x8mlZrebEbp/kF0BpAITOW3T0yPajfw1lG2UW4OiANvfU W5lxmg6JE2UYc93NwWqmbm781YgLuq0= X-Google-Smtp-Source: AA6agR7pyxVvIsqWfsH/Be21MXnfp89ZnfzdFwcmP6xY5ZELheU7YsepEsJfNHdTi8YcFZdZEwbo3g== X-Received: by 2002:a5d:634e:0:b0:225:3719:3f37 with SMTP id b14-20020a5d634e000000b0022537193f37mr13363796wrw.446.1661342479616; Wed, 24 Aug 2022 05:01:19 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.01.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:01:19 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 33/37] gccrs: add lang-spec.h Date: Wed, 24 Aug 2022 12:59:52 +0100 Message-Id: <20220824115956.737931-34-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-12.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron This specifies the extensions of the Rust language. --- gcc/rust/lang-specs.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 gcc/rust/lang-specs.h diff --git a/gcc/rust/lang-specs.h b/gcc/rust/lang-specs.h new file mode 100644 index 00000000000..9b14a559dd6 --- /dev/null +++ b/gcc/rust/lang-specs.h @@ -0,0 +1,26 @@ +/* lang-specs.h -- gcc driver specs 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 + . */ + +/* This is the contribution to the `default_compilers' array in gcc.cc + for the Rust language. */ + +{".rs", "@rs", 0, 1, 0}, + {"@rs", + "rust1 %i %(cc1_options) %{I*} %{L*} %D %{!fsyntax-only:%(invoke_as)}", 0, 1, + 0}, From patchwork Wed Aug 24 11:59:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56992 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 B17C2382E4F7 for ; Wed, 24 Aug 2022 12:05:07 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com [IPv6:2a00:1450:4864:20::42e]) by sourceware.org (Postfix) with ESMTPS id 7C9C138A90AA; Wed, 24 Aug 2022 12:01:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 7C9C138A90AA Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x42e.google.com with SMTP id a4so20521374wrq.1; Wed, 24 Aug 2022 05:01:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=rCjpV2ZCNEapwjgvPvjdsWbWm7LPTueLWr2pAEg47HI=; b=DO8lYnJvJuWFye1/Us567Elzq5LjkjwYuoEJZqfRTpNX1xOB1Paw+FqRm7ryz/OtzL dgkx/npBdj3PZ0zumpXaT8Zbe7xmt63Tcf1U5JRZgpbIbsKXm6mUBVCGzFQG6U1vgP9W jC/p6zot8v+nvu8NOTS70NFYawvXoMBYAQ3wEvHHZQK2sNywooYBjlYghRmLUf+S599r SXoeusHKGjYxZYtYdo6pER7gQWjKdq8GGFdDOjAcf0ba1nIj/sKBKwZGGVo6C0091o1S OMQBSz8dgijkxMOcF+HNSI52GrKPQ1Spa4oU2BwnMNW3lCVXyon6vOMeoi0rTIjnLkx5 h7aA== 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; bh=rCjpV2ZCNEapwjgvPvjdsWbWm7LPTueLWr2pAEg47HI=; b=2BkjDF+BTA16FObmfDJyCOeLMTgJONae8gMP3pG+TLDBtdGtubtdo1KsChbal6pDQ/ jEIWkiIDrurrYZFvdWwAJOuwfeHYEHKNWChCrw5FpaV6hoGCmHZVG5+jcAb056rCnYvB HnBBafEStJMNzzxtm39IaNPMxcN+S10evUxytS0PC1+JWKFDK5u9aILjezHphePd/qG6 dapK1sJbVndBj7ocaAvtBGSLTtnOXJIwiSbj85quYBv58RrN+UNZKv+q3IamSSuDyuef 5H08Ti2RxO4BQkhwi6pjUE38nPhG5Pc9GMsNeJwwmEtO7yjH4K9H5upNexnWk57jQ2bR 2fXQ== X-Gm-Message-State: ACgBeo1kG3AiVzFD5iUwAdqVp+cibePFRGl8rPhYc88YqwUeVhsZnBg+ 8+PP5m9VPlmcUVQr9/PBM7Ixr8OQaN0= X-Google-Smtp-Source: AA6agR4bMxL2fN1gunI+dgvDc0F6qC6TuQsm4RF49HNqDg7aOm2AQk4sUqf+nNIU6RaHzYyxWcIrXw== X-Received: by 2002:a05:6000:1e0e:b0:225:4e27:b806 with SMTP id bj14-20020a0560001e0e00b002254e27b806mr9451955wrb.605.1661342480823; Wed, 24 Aug 2022 05:01:20 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.01.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:01:20 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 34/37] gccrs: add lang.opt Date: Wed, 24 Aug 2022 12:59:53 +0100 Message-Id: <20220824115956.737931-35-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-12.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron We have some rust specific langugage options note -fwrapv is enabled by default in the code. We are trying to respect options such as -Wunused-result which we get by porting over c++ no-discard for rust's must-use attribute, so we have enabled these by default directly here. --- gcc/rust/lang.opt | 118 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 gcc/rust/lang.opt diff --git a/gcc/rust/lang.opt b/gcc/rust/lang.opt new file mode 100644 index 00000000000..1f6855ede1d --- /dev/null +++ b/gcc/rust/lang.opt @@ -0,0 +1,118 @@ +; Options for the Rust front end. +; Copyright (C) 2003-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 +; . + +; See the GCC internals manual for a description of this file's format. + +; Please try to keep this file in ASCII collating order. + +; Describes command-line options used by this frontend + +Language +Rust + +I +Rust Joined Separate +; Documented in c.opt + +L +Rust Joined Separate +; Not documented + +Wall +Rust +; Documented in c.opt + +Wunused-variable +Rust Var(warn_unused_variable) Init(1) Warning +; documented in common.opt + +Wunused-const-variable +Rust Warning Alias(Wunused-const-variable=, 2, 0) +Warn when a const variable is unused. + +Wunused-const-variable= +Rust Joined RejectNegative UInteger Var(warn_unused_const_variable) Init(1) Warning LangEnabledBy(Rust,Wunused-variable, 1, 0) IntegerRange(0, 2) +Warn when a const variable is unused. + +Wunused-result +Rust Var(warn_unused_result) Init(1) Warning +Warn if a caller of a function, marked with attribute warn_unused_result, does not use its return value. + +frust-crate= +Rust Joined RejectNegative +-frust-crate= Set the crate name for the compilation + +frust-debug +Rust Var(flag_rust_debug) +Dump various Rust front end internals. + +frust-dump- +Rust Joined RejectNegative +-frust-dump- Dump Rust frontend internal information. + +frust-max-recursion-depth= +Rust RejectNegative Type(int) Var(rust_max_recursion_depth) Init(64) +-frust-max-recursion-depth=integer + +frust-mangling= +Rust Joined RejectNegative Enum(frust_mangling) Var(flag_rust_mangling) +-frust-mangling=[legacy|v0] Choose which version to use for name mangling + +Enum +Name(frust_mangling) Type(int) UnknownError(unknown rust mangling option %qs) + +EnumValue +Enum(frust_mangling) String(legacy) Value(0) + +EnumValue +Enum(frust_mangling) String(v0) Value(1) + +frust-cfg= +Rust Joined RejectNegative +-frust-cfg= Set a config expansion option + +frust-edition= +Rust Joined RejectNegative Enum(frust_edition) Var(flag_rust_edition) +-frust-edition=[2015|2018|2021] Choose which edition to use when compiling rust code + +Enum +Name(frust_edition) Type(int) UnknownError(unknown rust edition %qs) + +EnumValue +Enum(frust_edition) String(2015) Value(0) + +EnumValue +Enum(frust_edition) String(2018) Value(1) + +EnumValue +Enum(frust_edition) String(2021) Value(2) + +frust-embed-metadata +Rust Var(flag_rust_embed_metadata) +Flag to enable embeding metadata directly into object files + +frust-metadata-output= +Rust Joined RejectNegative +-frust-metadata-output= Path to output crate metadata + +o +Rust Joined Separate +; Documented in common.opt + +; This comment is to ensure we retain the blank line above. From patchwork Wed Aug 24 11:59:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 57005 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 DBE8A38515DC for ; Wed, 24 Aug 2022 12:08:08 +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 0C05B3815FCF; Wed, 24 Aug 2022 12:01:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 0C05B3815FCF Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x435.google.com with SMTP id u5so12681504wrt.11; Wed, 24 Aug 2022 05:01:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=HFHa4LZ3e3KHuS1DXqL9Nsw+dX6mGmMp7zMZIZBAhe4=; b=kZwQv0hrqDxw/HhGr/jzUvGdzrEtGccMcMUek2EoGvidStoCXGYhQVvUFOv2p0FNut rSdZn1rGcR7+bc0kvlsydLfJInY1sjOue9xhchoNlmZenrHu+snMOcg4MBY31o2pc6AQ JnnTcb/pmTy2VGpoBrh4cvjgTm1riwwCtzDzUoSfk2M0awZ09lEs86Z9oNoQS+cHsDDp 8dvgcEdCfYQKkbxBCZkg1yQcWWYye+VGaMyM92yImlsJ4ScTFCPRObv7IsIBDOZF1XTD vSIzQlua4+q3X29aRAg6dx4/Cn99qiEseMRkklUP+4Qff/+7UnnFG47vC16gz4NLvlK1 yG2Q== 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; bh=HFHa4LZ3e3KHuS1DXqL9Nsw+dX6mGmMp7zMZIZBAhe4=; b=0wusULj09lH+ZHwzhEuVFw+BV+beYCOLZt84vSHZMH78FTzCJ2luIhckMFSAXqWMNV fDwYm5PSApT5hBy7Y6jWRimrjjosxOL62IjYKuBbApbYtSWDwchrTtGEjnJOLyG1i+uL GohB11fsSgPo1newlYwuKJVX2FHw72jzX2t4oh87HLyfC+jSwBc5HcGeWnag2AJjNJQG UJAeDrclectdBMiD2uuV3lRwWu6/TPNUQrLI0BDJT9Co02smYfJb+EE/QsZwDIXhuf2l OS8KSFRt7Z8dsoKqR5p9yR26GAzPIDBOdcuaSzHXprf/nn4OLuAsRTDrjmyCK1WtIBn8 n6xw== X-Gm-Message-State: ACgBeo1Hj12FjnxvKOqKX6HI+83rJHp2XaI8lNW23ASTdu6pypnaIsoc 9BZNtIhpkO9wGplGJEAWiYGi7/CgvQ0= X-Google-Smtp-Source: AA6agR5FU3LFYzsH2LeznEB4qfrZObBn//4/wLBEGu1XRT7tUq0W0MCWC5lKCwtDqQS+foNoRbWyRA== X-Received: by 2002:adf:eb10:0:b0:225:70d5:e994 with SMTP id s16-20020adfeb10000000b0022570d5e994mr1642095wrn.425.1661342482202; Wed, 24 Aug 2022 05:01:22 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.01.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:01:21 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 35/37] gccrs: add compiler driver Date: Wed, 24 Aug 2022 12:59:54 +0100 Message-Id: <20220824115956.737931-36-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-12.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron Our compiler driver is pretty simple so far, the key piece to enforce is that a compilation unit in Rust is the whole crate so the process for compiling rust means pointing the compiler at the main entry point such as src/lib.rs or src/main.rs where the expansion pass takes over loading the other source files to include them in the crate. --- gcc/rust/rustspec.cc | 191 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 gcc/rust/rustspec.cc diff --git a/gcc/rust/rustspec.cc b/gcc/rust/rustspec.cc new file mode 100644 index 00000000000..b05f8ae5454 --- /dev/null +++ b/gcc/rust/rustspec.cc @@ -0,0 +1,191 @@ +/* rustspec.c -- Specific flags and argument handling of the gcc Rust front end. + 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 "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "opts.h" + +// satisfy intellisense +#include "options.h" + +/* This bit is set if we saw a `-xfoo' language specification. */ +#define LANGSPEC (1 << 1) +/* This bit is set if they did `-lc'. */ +#define WITHLIBC (1 << 2) +/* Skip this option. */ +#define SKIPOPT (1 << 3) + +void +lang_specific_driver (struct cl_decoded_option **in_decoded_options, + unsigned int *in_decoded_options_count, + int *in_added_libraries) +{ + unsigned int i, j; + + /* The new argument list will be contained in this. */ + struct cl_decoded_option *new_decoded_options; + + /* "-lc" if it appears on the command line. */ + const struct cl_decoded_option *saw_libc = 0; + + /* An array used to flag each argument that needs a bit set for + LANGSPEC or WITHLIBC. */ + int *args; + + /* True if we saw -static. */ + int static_link = 0; + + /* True if we should add -shared-libgcc to the command-line. */ + int shared_libgcc = 1; + + /* The total number of arguments with the new stuff. */ + unsigned int argc; + + /* The argument list. */ + struct cl_decoded_option *decoded_options; + + /* The number of libraries added in. */ + int added_libraries; + + /* The total number of arguments with the new stuff. */ + int num_args = 1; + + /* Whether the -o option was used. */ + bool saw_opt_o = false; + + /* The first input file with an extension of .rs. */ + const char *first_rust_file = NULL; + + argc = *in_decoded_options_count; + decoded_options = *in_decoded_options; + added_libraries = *in_added_libraries; + + args = XCNEWVEC (int, argc); + + for (i = 1; i < argc; i++) + { + const char *arg = decoded_options[i].arg; + + switch (decoded_options[i].opt_index) + { + case OPT_l: + if (strcmp (arg, "c") == 0) + args[i] |= WITHLIBC; + break; + + case OPT_o: + saw_opt_o = true; + break; + + case OPT_static: + static_link = 1; + break; + + case OPT_static_libgcc: + shared_libgcc = 0; + break; + + case OPT_SPECIAL_input_file: + if (first_rust_file == NULL) + { + int len; + + len = strlen (arg); + if (len > 3 && strcmp (arg + len - 3, ".rs") == 0) + first_rust_file = arg; + } + else + { + // FIXME: ARTHUR: Do we want to error here? If there's already one + // file? + // How do we error here? Do we want to instead just handle that in + // the session manager? + } + + break; + } + } + + /* There's no point adding -shared-libgcc if we don't have a shared + libgcc. */ +#ifndef ENABLE_SHARED_LIBGCC + shared_libgcc = 0; +#endif + + /* Make sure to have room for the trailing NULL argument. */ + num_args = argc + shared_libgcc * 5 + 10; + new_decoded_options = XNEWVEC (struct cl_decoded_option, num_args); + + i = 0; + j = 0; + + /* Copy the 0th argument, i.e., the name of the program itself. */ + new_decoded_options[j++] = decoded_options[i++]; + + /* NOTE: We start at 1 now, not 0. */ + while (i < argc) + { + new_decoded_options[j] = decoded_options[i]; + + if (!saw_libc && (args[i] & WITHLIBC)) + { + --j; + saw_libc = &decoded_options[i]; + } + + if ((args[i] & SKIPOPT) != 0) + --j; + + i++; + j++; + } + + /* If we didn't see a -o option, add one. This is because we need + the driver to pass all .rs files to rust1. Without a -o option the + driver will invoke rust1 separately for each input file. FIXME: + This should probably use some other interface to force the driver + to set combine_inputs. */ + if (!saw_opt_o) + { + generate_option (OPT_o, "a.out", 1, CL_DRIVER, &new_decoded_options[j]); + j++; + } + + if (saw_libc) + new_decoded_options[j++] = *saw_libc; + if (shared_libgcc && !static_link) + generate_option (OPT_shared_libgcc, NULL, 1, CL_DRIVER, + &new_decoded_options[j++]); + + *in_decoded_options_count = j; + *in_decoded_options = new_decoded_options; + *in_added_libraries = added_libraries; +} + +/* Called before linking. Returns 0 on success and -1 on failure. */ +int +lang_specific_pre_link (void) /* Not used for Rust. */ +{ + return 0; +} + +/* Number of extra output files that lang_specific_pre_link may generate. */ +int lang_specific_extra_outfiles = 0; /* Not used for Rust. */ From patchwork Wed Aug 24 11:59:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 56996 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 C1E2A382CDC2 for ; Wed, 24 Aug 2022 12:05:56 +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 9574738AA269; Wed, 24 Aug 2022 12:01:26 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 9574738AA269 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wr1-x430.google.com with SMTP id d16so15197815wrr.3; Wed, 24 Aug 2022 05:01:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=veq1tPhhbKvODBxz0QE9ivZKNZJW9uU9PVLAbG3YCJQ=; b=T7XhRAxfFu5mNjFrT1T1VikPYG5g1w+sPQoH1NQsTgwVf1ubJ4lCHqCCn1mQbJPDko Qv56seNtn1bP+zMV38DMpem0orSVkwWn+n1vc4nUZ6GwcQyv+2Hof02JPfuFWJSIeyPv UV/xp08XyxUXa/Kxxv/RyuFtY5Sf5lc0LJjhIm4W6wiDyJn5ddmWcfQl9YxSaEpriAR5 RFjt3jLFOLQdhTOWJ6aF3iMcPjy07tmhC+TwGDz1eRS+UFsQkyi8GrezzrEFNd76dh73 4nM5OU4OB/FYUq2nmITswikbwsNwFWibv6ekrzOLmwdvm12fWSZjfaWAb7rrDfpa0z7V pSnA== 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; bh=veq1tPhhbKvODBxz0QE9ivZKNZJW9uU9PVLAbG3YCJQ=; b=nQWf+2I+geJMGr3+UuuhnOp0lm0iwE4eOZcwGSPiF9TfkRN4X0zMy2SU4f1hlNfzdw IA+ejMMuW6qBFHinX0XmFZ07UGyj1x28CLCk8li8r9GbZDwBLELTDb0m4Ik8wd/IEEbe u6rh9c3x5mSiq6NHYE262zMeAR1R/MTM5Zx2Zggg66ygaqQ6D9AEwGPKrs3UcOAVxVUv UB6DrymOQ3qGaKOMmIOAPsUSEq1bkEus0geFDeCZmrq60SUzAZsdMib5RpEUIT9eQ5gy E+FRVdMXgq6k+G+MLvYRVq7MsdjwU2Fzp7QJh5DjCDie6uqjstupQqK2W7PzjvLVAI1m Nc3w== X-Gm-Message-State: ACgBeo1OtOWQyseUedTWFRaJS5OVSUaW9XlAUewaAKgsmkLyTqPE8dvd nZAHS3emvSmp27SFh0f2sCoaueovXQk= X-Google-Smtp-Source: AA6agR7mAYnuayPlX0tJUHMdiRtL0mDHf5CH64wEJ849Xtxc3CcTlFmxRis71fNAHlMjKKPcDvFwjw== X-Received: by 2002:a5d:5a9d:0:b0:225:2783:d6f1 with SMTP id bp29-20020a5d5a9d000000b002252783d6f1mr16352393wrb.385.1661342483625; Wed, 24 Aug 2022 05:01:23 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.01.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:01:22 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 36/37] gccrs: compiler proper interface kicks off the pipeline Date: Wed, 24 Aug 2022 12:59:55 +0100 Message-Id: <20220824115956.737931-37-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-12.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron This is a wrapper to get out of C land in the rust-lang.cc and into our class hierarchy for the rust front-end. We expect that the front-end only support one source file input as the expansion pass will attempt to resolve that relative pass and parse accordingly. The main missing piece here is that we are using saw_errors() to return early which is unnecessary but as our error handling has been improving over time we will start to take advantage of error node in our type system as well as error_mark_node from GCC. The caveat being that our lints/checks expect no errors and will throw an assertion. --- gcc/rust/rust-lang.cc | 452 ++++++++++++ gcc/rust/rust-session-manager.cc | 1189 ++++++++++++++++++++++++++++++ gcc/rust/rust-session-manager.h | 358 +++++++++ 3 files changed, 1999 insertions(+) create mode 100644 gcc/rust/rust-lang.cc create mode 100644 gcc/rust/rust-session-manager.cc create mode 100644 gcc/rust/rust-session-manager.h diff --git a/gcc/rust/rust-lang.cc b/gcc/rust/rust-lang.cc new file mode 100644 index 00000000000..c9af790f66b --- /dev/null +++ b/gcc/rust/rust-lang.cc @@ -0,0 +1,452 @@ +// 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 +// . + +#include "rust-diagnostics.h" +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "tree.h" +#include "gimple-expr.h" +#include "diagnostic.h" +#include "opts.h" +#include "fold-const.h" +#include "gimplify.h" +#include "stor-layout.h" +#include "debug.h" +#include "convert.h" +#include "langhooks.h" +#include "langhooks-def.h" + +#include "selftest.h" +#include "rust-cfg-parser.h" +#include "rust-privacy-ctx.h" +#include "rust-ast-resolve-item.h" +#include "rust-optional.h" + +#include +// note: header files must be in this order or else forward declarations don't +// work properly. Kinda dumb system, but have to live with it. clang-format +// seems to mess it up +/* Order: config, system, coretypes, target, tree, gimple-expr, diagnostic, + * opts, fold-const, gimplify, stor-layout, debug, convert, langhooks, + * langhooks-def */ + +// FIXME: test saving intellisense +#include "options.h" + +// version check to stop compiling if c++ isn't c++11 or higher +#if __cplusplus < 201103 +#error \ + "GCC Rust frontend requires C++11 or higher. You can compile the g++ frontend first and then compile the Rust frontend using that." +#endif +// TODO: is this best way to do it? Is it allowed? (should be) + +/* General TODOs: + * - convert all copies of expensive-to-copy (deep copy) AST objects into + * moves, if possible. Don't remove clone functionality - it may be required for + * e.g. HIR conversion. + */ + +#include "rust-system.h" +#include "rust-session-manager.h" + +// Language-dependent contents of a type. GTY() mark used for garbage collector. +struct GTY (()) lang_type +{ +}; + +// Language-dependent contents of a decl. +struct GTY (()) lang_decl +{ +}; + +// Language-dependent contents of an identifier. This must include a +// tree_identifier. +struct GTY (()) lang_identifier +{ + struct tree_identifier common; +}; + +// The resulting tree type. +union GTY (( + desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"), + chain_next ( + "CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), " + "TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL"))) + lang_tree_node +{ + union tree_node GTY ((tag ("0"), desc ("tree_node_structure (&%h)"))) generic; + struct lang_identifier GTY ((tag ("1"))) identifier; +}; + +// We don't use language_function. +struct GTY (()) language_function +{ +}; + +// has to be in same compilation unit as session, so here for now +void +rust_add_target_info (const char *key, const char *value) +{ + sorry ("TODO"); + + Rust::Session::get_instance ().options.target_data.insert_key_value_pair ( + key, value); +} + +/* Language hooks. */ + +/* Initial lang hook called (possibly), used for initialisation. + * Must call build_common_tree_nodes, set_sizetype, build_common_tree_nodes_2, + * and build_common_builtin_nodes, as well as set global variable + * void_list_node. Apparently called after option handling? */ +static bool +grs_langhook_init (void) +{ + /* Something to do with this: + This allows the code in d-builtins.cc to not have to worry about + converting (C signed char *) to (D char *) for string arguments of + built-in functions. The parameter (signed_char = false) specifies + whether char is signed. */ + build_common_tree_nodes (false); + + // Creates a new TREE_LIST node with purpose NULL_TREE and value + // void_type_node + void_list_node = build_tree_list (NULL_TREE, void_type_node); + + // Builds built-ins for middle-end after all front-end built-ins are already + // instantiated + build_common_builtin_nodes (); + + mpfr_set_default_prec (128); + + using_eh_for_cleanups (); + + // initialise compiler session + Rust::Session::get_instance ().init (); + + return true; +} + +/* The option mask (something to do with options for specific frontends or + * something). */ +static unsigned int +grs_langhook_option_lang_mask (void) +{ + return CL_Rust; +} + +/* Initialize the options structure. */ +static void +grs_langhook_init_options_struct (struct gcc_options *opts) +{ + /* Operations are always wrapping in Rust, even on signed integer. This is + * useful for the low level wrapping_{add, sub, mul} intrinsics, not for + * regular arithmetic operations which are checked for overflow anyway using + * builtins */ + opts->x_flag_wrapv = 1; + + // nothing yet - used by frontends to change specific options for the language + Rust::Session::get_instance ().init_options (); +} + +/* Main entry point for front-end, apparently. Finds input file names in global + * vars in_fnames and num_in_fnames. From this, frontend can take over and do + * actual parsing and initial compilation. This function must create a complete + * parse tree in a global var, and then return. + * + * Some consider this the "start of compilation". */ +static void +grs_langhook_parse_file (void) +{ + rust_debug ("Preparing to parse files. "); + + Rust::Session::get_instance ().handle_input_files (num_in_fnames, in_fnames); +} + +/* Seems to get the exact type for a specific type - e.g. for scalar float with + * 32-bit bitsize, it returns float, and for 64-bit bitsize, it returns double. + * Used to map RTL nodes to machine modes or something like that. */ +static tree +grs_langhook_type_for_mode (machine_mode mode, int unsignedp) +{ + // TODO: change all this later to match rustc types + if (mode == TYPE_MODE (float_type_node)) + return float_type_node; + + if (mode == TYPE_MODE (double_type_node)) + return double_type_node; + + if (mode == TYPE_MODE (intQI_type_node)) // quarter integer mode - single byte + // treated as integer + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + if (mode + == TYPE_MODE (intHI_type_node)) // half integer mode - two-byte integer + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + if (mode + == TYPE_MODE (intSI_type_node)) // single integer mode - four-byte integer + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + if (mode + == TYPE_MODE ( + intDI_type_node)) // double integer mode - eight-byte integer + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + if (mode + == TYPE_MODE (intTI_type_node)) // tetra integer mode - 16-byte integer + return unsignedp ? unsigned_intTI_type_node : intTI_type_node; + + if (mode == TYPE_MODE (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + + if (mode == TYPE_MODE (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + + if (mode == TYPE_MODE (long_long_integer_type_node)) + return unsignedp ? long_long_unsigned_type_node + : long_long_integer_type_node; + + if (COMPLEX_MODE_P (mode)) + { + if (mode == TYPE_MODE (complex_float_type_node)) + return complex_float_type_node; + if (mode == TYPE_MODE (complex_double_type_node)) + return complex_double_type_node; + if (mode == TYPE_MODE (complex_long_double_type_node)) + return complex_long_double_type_node; + if (mode == TYPE_MODE (complex_integer_type_node) && !unsignedp) + return complex_integer_type_node; + } + /* gcc_unreachable */ + return NULL; +} + +// Record a builtin function. We just ignore builtin functions. +static tree +grs_langhook_builtin_function (tree decl ATTRIBUTE_UNUSED) +{ + return decl; +} + +/* Return true if we are in the global binding level (which is never, + * apparently). */ +static bool +grs_langhook_global_bindings_p (void) +{ + // return current_function_decl == NULL_TREE; + // gcc_unreachable(); + // return true; + return false; +} + +/* Push a declaration into the current binding level. We can't + usefully implement this since we don't want to convert from tree + back to one of our internal data structures. I think the only way + this is used is to record a decl which is to be returned by + getdecls, and we could implement it for that purpose if + necessary. */ +static tree +grs_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED) +{ + gcc_unreachable (); + return NULL; +} + +/* This hook is used to get the current list of declarations as trees. + We don't support that; instead we use the write_globals hook. This + can't simply crash because it is called by -gstabs. */ +static tree +grs_langhook_getdecls (void) +{ + // gcc_unreachable(); + return NULL; +} + +// Handle Rust-specific options. Return false if nothing happened. +static bool +grs_langhook_handle_option ( + size_t scode, const char *arg, HOST_WIDE_INT value, int kind ATTRIBUTE_UNUSED, + location_t loc ATTRIBUTE_UNUSED, + const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED) +{ + // Convert integer code to lang.opt enum codes with names. + enum opt_code code = (enum opt_code) scode; + + // Delegate to session manager + return Rust::Session::get_instance ().handle_option (code, arg, value, kind, + loc, handlers); +} + +/* Run after parsing options. */ +static bool +grs_langhook_post_options (const char **pfilename ATTRIBUTE_UNUSED) +{ + // can be used to override other options if required + + // satisfies an assert in init_excess_precision in toplev.cc + if (flag_excess_precision /*_cmdline*/ == EXCESS_PRECISION_DEFAULT) + flag_excess_precision /*_cmdline*/ = EXCESS_PRECISION_STANDARD; + + /* Returning false means that the backend should be used. */ + return false; +} + +/* Rust-specific gimplification. May need to gimplify e.g. + * CALL_EXPR_STATIC_CHAIN */ +static int +grs_langhook_gimplify_expr (tree *expr_p ATTRIBUTE_UNUSED, + gimple_seq *pre_p ATTRIBUTE_UNUSED, + gimple_seq *post_p ATTRIBUTE_UNUSED) +{ + if (TREE_CODE (*expr_p) == CALL_EXPR + && CALL_EXPR_STATIC_CHAIN (*expr_p) != NULL_TREE) + gimplify_expr (&CALL_EXPR_STATIC_CHAIN (*expr_p), pre_p, post_p, + is_gimple_val, fb_rvalue); + return GS_UNHANDLED; +} + +static tree +grs_langhook_eh_personality (void) +{ + static tree personality_decl; + if (personality_decl == NULL_TREE) + { + personality_decl = build_personality_function ("gccrs"); + rust_preserve_from_gc (personality_decl); + } + return personality_decl; +} + +tree +convert (tree type, tree expr) +{ + if (type == error_mark_node || expr == error_mark_node + || TREE_TYPE (expr) == error_mark_node) + return error_mark_node; + + if (type == TREE_TYPE (expr)) + return expr; + + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr))) + return fold_convert (type, expr); + + switch (TREE_CODE (type)) + { + case VOID_TYPE: + case BOOLEAN_TYPE: + return fold_convert (type, expr); + case INTEGER_TYPE: + return fold (convert_to_integer (type, expr)); + case POINTER_TYPE: + return fold (convert_to_pointer (type, expr)); + case REAL_TYPE: + return fold (convert_to_real (type, expr)); + case COMPLEX_TYPE: + return fold (convert_to_complex (type, expr)); + default: + break; + } + + gcc_unreachable (); +} + +/* FIXME: This is a hack to preserve trees that we create from the + garbage collector. */ + +static GTY (()) tree rust_gc_root; + +void +rust_preserve_from_gc (tree t) +{ + rust_gc_root = tree_cons (NULL_TREE, t, rust_gc_root); +} + +/* Convert an identifier for use in an error message. */ + +const char * +rust_localize_identifier (const char *ident) +{ + return identifier_to_locale (ident); +} + +/* The language hooks data structure. This is the main interface between the GCC + * front-end and the GCC middle-end/back-end. A list of language hooks could be + * found in /langhooks.h + */ +#undef LANG_HOOKS_NAME +#undef LANG_HOOKS_INIT +#undef LANG_HOOKS_OPTION_LANG_MASK +#undef LANG_HOOKS_INIT_OPTIONS_STRUCT +#undef LANG_HOOKS_HANDLE_OPTION +#undef LANG_HOOKS_POST_OPTIONS +#undef LANG_HOOKS_PARSE_FILE +#undef LANG_HOOKS_TYPE_FOR_MODE +#undef LANG_HOOKS_BUILTIN_FUNCTION +#undef LANG_HOOKS_GLOBAL_BINDINGS_P +#undef LANG_HOOKS_PUSHDECL +#undef LANG_HOOKS_GETDECLS +#undef LANG_HOOKS_WRITE_GLOBALS +#undef LANG_HOOKS_GIMPLIFY_EXPR +#undef LANG_HOOKS_EH_PERSONALITY + +#define LANG_HOOKS_NAME "GNU Rust" +#define LANG_HOOKS_INIT grs_langhook_init +#define LANG_HOOKS_OPTION_LANG_MASK grs_langhook_option_lang_mask +#define LANG_HOOKS_INIT_OPTIONS_STRUCT grs_langhook_init_options_struct +#define LANG_HOOKS_HANDLE_OPTION grs_langhook_handle_option +#define LANG_HOOKS_POST_OPTIONS grs_langhook_post_options +/* Main lang-hook, apparently. Finds input file names in global vars in_fnames + * and num_in_fnames From this, frontend can take over and do actual parsing and + * initial compilation. + * This hook must create a complete parse tree in a global var, and then return. + */ +#define LANG_HOOKS_PARSE_FILE grs_langhook_parse_file +#define LANG_HOOKS_TYPE_FOR_MODE grs_langhook_type_for_mode +#define LANG_HOOKS_BUILTIN_FUNCTION grs_langhook_builtin_function +#define LANG_HOOKS_GLOBAL_BINDINGS_P grs_langhook_global_bindings_p +#define LANG_HOOKS_PUSHDECL grs_langhook_pushdecl +#define LANG_HOOKS_GETDECLS grs_langhook_getdecls +#define LANG_HOOKS_GIMPLIFY_EXPR grs_langhook_gimplify_expr +#define LANG_HOOKS_EH_PERSONALITY grs_langhook_eh_personality + +#if CHECKING_P + +#undef LANG_HOOKS_RUN_LANG_SELFTESTS +#define LANG_HOOKS_RUN_LANG_SELFTESTS selftest::run_rust_tests + +namespace selftest { + +void +run_rust_tests () +{ + // Call tests for the rust frontend here + rust_cfg_parser_test (); + rust_privacy_ctx_test (); + rust_crate_name_validation_test (); + rust_simple_path_resolve_test (); + rust_optional_test (); +} +} // namespace selftest + +#endif /* !CHECKING_P */ + +// Expands all LANG_HOOKS_x of GCC +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; + +// These are for GCC's garbage collector to work properly or something +#include "gt-rust-rust-lang.h" +#include "gtype-rust.h" diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc new file mode 100644 index 00000000000..6d7f1a85f19 --- /dev/null +++ b/gcc/rust/rust-session-manager.cc @@ -0,0 +1,1189 @@ +// 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 +// . + +#include "rust-session-manager.h" +#include "rust-diagnostics.h" +#include "rust-unsafe-checker.h" +#include "rust-lex.h" +#include "rust-parse.h" +#include "rust-macro-expand.h" +#include "rust-ast-resolve.h" +#include "rust-ast-lower.h" +#include "rust-hir-type-check.h" +#include "rust-privacy-check.h" +#include "rust-const-checker.h" +#include "rust-tycheck-dump.h" +#include "rust-compile.h" +#include "rust-cfg-parser.h" +#include "rust-lint-scan-deadcode.h" +#include "rust-lint-unused-var.h" +#include "rust-hir-dump.h" +#include "rust-ast-dump.h" +#include "rust-export-metadata.h" +#include "rust-imports.h" +#include "rust-extern-crate.h" +#include "rust-attributes.h" + +#include "diagnostic.h" +#include "input.h" +#include "selftest.h" +#include "target.h" + +extern bool +saw_errors (void); + +extern Linemap * +rust_get_linemap (); + +extern Backend * +rust_get_backend (); + +namespace Rust { + +const char *kLexDumpFile = "gccrs.lex.dump"; +const char *kASTDumpFile = "gccrs.ast.dump"; +const char *kASTPrettyDumpFile = "gccrs.ast-pretty.dump"; +const char *kASTExpandedDumpFile = "gccrs.ast-expanded.dump"; +const char *kHIRDumpFile = "gccrs.hir.dump"; +const char *kHIRPrettyDumpFile = "gccrs.hir-pretty.dump"; +const char *kHIRTypeResolutionDumpFile = "gccrs.type-resolution.dump"; +const char *kTargetOptionsDumpFile = "gccrs.target-options.dump"; + +const std::string kDefaultCrateName = "rust_out"; +const size_t kMaxNameLength = 64; + +Session & +Session::get_instance () +{ + static Session instance; + return instance; +} + +static std::string +infer_crate_name (const std::string &filename) +{ + if (filename == "-") + return kDefaultCrateName; + + std::string crate = std::string (filename); + size_t path_sep = crate.find_last_of (file_separator); + + // find the base filename + if (path_sep != std::string::npos) + crate.erase (0, path_sep + 1); + + // find the file stem name (remove file extension) + size_t ext_position = crate.find_last_of ('.'); + if (ext_position != std::string::npos) + crate.erase (ext_position); + + // Replace all the '-' symbols with '_' per Rust rules + for (auto &c : crate) + { + if (c == '-') + c = '_'; + } + return crate; +} + +/* Validate the crate name using the ASCII rules + TODO: Support Unicode version of the rules */ + +static bool +validate_crate_name (const std::string &crate_name, Error &error) +{ + if (crate_name.empty ()) + { + error = Error (Location (), "crate name cannot be empty"); + return false; + } + if (crate_name.length () > kMaxNameLength) + { + error = Error (Location (), "crate name cannot exceed %lu characters", + (unsigned long) kMaxNameLength); + return false; + } + for (auto &c : crate_name) + { + if (!(ISALNUM (c) || c == '_')) + { + error = Error (Location (), + "invalid character %<%c%> in crate name: %<%s%>", c, + crate_name.c_str ()); + return false; + } + } + return true; +} + +void +Session::init () +{ + options.target_data.insert_key_value_pair ("target_pointer_width", + std::to_string (POINTER_SIZE)); + options.target_data.insert_key_value_pair ("target_endian", BYTES_BIG_ENDIAN + ? "big" + : "little"); + + // setup singleton linemap + linemap = rust_get_linemap (); + + // setup backend to GCC GIMPLE + backend = rust_get_backend (); + + // setup mappings class + mappings = Analysis::Mappings::get (); +} + +/* Initialise default options. Actually called before handle_option, unlike init + * itself. */ +void +Session::init_options () +{} + +// Handle option selection. +bool +Session::handle_option ( + enum opt_code code, const char *arg, HOST_WIDE_INT value ATTRIBUTE_UNUSED, + int kind ATTRIBUTE_UNUSED, location_t loc ATTRIBUTE_UNUSED, + const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED) +{ + // used to store whether results of various stuff are successful + bool ret = true; + + // Handles options as listed in lang.opt. + switch (code) + { + case OPT_I: + case OPT_L: { + // TODO: add search path + const std::string p = std::string (arg); + add_search_path (p); + } + break; + + case OPT_frust_crate_: + // set the crate name + if (arg != nullptr) + { + auto error = Error (Location (), std::string ()); + if ((ret = validate_crate_name (arg, error))) + { + options.set_crate_name (arg); + options.crate_name_set_manually = true; + } + else + { + rust_assert (!error.message.empty ()); + error.emit_error (); + } + } + else + ret = false; + break; + + case OPT_frust_dump_: + // enable dump and return whether this was successful + if (arg != nullptr) + { + ret = enable_dump (std::string (arg)); + } + else + { + ret = false; + } + break; + + case OPT_frust_mangling_: + Compile::Mangler::set_mangling (flag_rust_mangling); + break; + + case OPT_frust_cfg_: { + auto string_arg = std::string (arg); + ret = handle_cfg_option (string_arg); + break; + } + + case OPT_frust_edition_: + options.set_edition (flag_rust_edition); + break; + + case OPT_frust_metadata_output_: + options.set_metadata_output (arg); + break; + + default: + break; + } + + return ret; +} + +bool +Session::handle_cfg_option (std::string &input) +{ + std::string key; + std::string value; + + // Refactor this if needed + if (!parse_cfg_option (input, key, value)) + { + rust_error_at ( + Location (), + "invalid argument to %<-frust-cfg%>: Accepted formats are " + "%<-frust-cfg=key%> or %<-frust-cfg=key=\"value\"%> (quoted)"); + return false; + } + + if (value.empty ()) + // rustc does not seem to error on dup key + options.target_data.insert_key (key); + else + options.target_data.insert_key_value_pair (key, value); + + return true; +} + +/* Enables a certain dump depending on the name passed in. Returns true if + * name is valid, false otherwise. */ +bool +Session::enable_dump (std::string arg) +{ + if (arg.empty ()) + { + rust_error_at ( + Location (), + "dump option was not given a name. choose %, %, " + "%, %, %, %," + " %, %, or %"); + return false; + } + + if (arg == "all") + { + options.enable_all_dump_options (); + } + else if (arg == "lex") + { + options.enable_dump_option (CompileOptions::LEXER_DUMP); + } + else if (arg == "parse") + { + options.enable_dump_option (CompileOptions::PARSER_AST_DUMP); + } + else if (arg == "ast-pretty") + { + options.enable_dump_option (CompileOptions::AST_DUMP_PRETTY); + } + else if (arg == "register_plugins") + { + options.enable_dump_option (CompileOptions::REGISTER_PLUGINS_DUMP); + } + else if (arg == "injection") + { + options.enable_dump_option (CompileOptions::INJECTION_DUMP); + } + else if (arg == "expansion") + { + options.enable_dump_option (CompileOptions::EXPANSION_DUMP); + } + else if (arg == "resolution") + { + options.enable_dump_option (CompileOptions::RESOLUTION_DUMP); + } + else if (arg == "target_options") + { + options.enable_dump_option (CompileOptions::TARGET_OPTION_DUMP); + } + else if (arg == "hir") + { + options.enable_dump_option (CompileOptions::HIR_DUMP); + } + else if (arg == "hir-pretty") + { + options.enable_dump_option (CompileOptions::HIR_DUMP_PRETTY); + } + else + { + rust_error_at ( + Location (), + "dump option %qs was unrecognised. choose %, %, " + "%, %, %, %," + " %, or %", + arg.c_str ()); + return false; + } + return true; +} + +/* Actual main entry point for front-end. Called from langhook to parse files. + */ +void +Session::handle_input_files (int num_files, const char **files) +{ + if (num_files != 1) + rust_fatal_error (Location (), + "only one file may be specified on the command line"); + + const auto &file = files[0]; + + if (options.crate_name.empty ()) + { + auto filename = "-"; + if (num_files > 0) + filename = files[0]; + + auto crate_name = infer_crate_name (filename); + rust_debug ("inferred crate name: %s", crate_name.c_str ()); + // set the preliminary crate name here + // we will figure out the real crate name in `handle_crate_name` + options.set_crate_name (crate_name); + } + + CrateNum crate_num = mappings->get_next_crate_num (options.get_crate_name ()); + mappings->set_current_crate (crate_num); + + rust_debug ("Attempting to parse file: %s", file); + compile_crate (file); +} + +void +Session::handle_crate_name (const AST::Crate &parsed_crate) +{ + auto mappings = Analysis::Mappings::get (); + auto crate_name_changed = false; + auto error = Error (Location (), std::string ()); + + for (const auto &attr : parsed_crate.inner_attrs) + { + if (attr.get_path () != "crate_name") + continue; + if (!attr.has_attr_input ()) + { + rust_error_at (attr.get_locus (), + "% accepts one argument"); + continue; + } + + auto &literal + = static_cast (attr.get_attr_input ()); + const auto &msg_str = literal.get_literal ().as_string (); + if (!validate_crate_name (msg_str, error)) + { + error.locus = attr.get_locus (); + error.emit_error (); + continue; + } + + auto options = Session::get_instance ().options; + if (options.crate_name_set_manually && (options.crate_name != msg_str)) + { + rust_error_at (attr.get_locus (), + "%<-frust-crate-name%> and %<#[crate_name]%> are " + "required to match, but %qs does not match %qs", + options.crate_name.c_str (), msg_str.c_str ()); + } + crate_name_changed = true; + options.set_crate_name (msg_str); + mappings->set_crate_name (mappings->get_current_crate (), msg_str); + } + + options.crate_name_set_manually |= crate_name_changed; + if (!options.crate_name_set_manually + && !validate_crate_name (options.crate_name, error)) + { + error.emit_error (); + rust_inform (linemap->get_location (0), + "crate name inferred from this file"); + } +} + +// Parses a single file with filename filename. +void +Session::compile_crate (const char *filename) +{ + RAIIFile file_wrap (filename); + if (!file_wrap.ok ()) + { + rust_error_at (Location (), "cannot open filename %s: %m", filename); + return; + } + + // parse file here + /* create lexer and parser - these are file-specific and so aren't instance + * variables */ + Lexer lex (filename, std::move (file_wrap), linemap); + Parser parser (lex); + + // generate crate from parser + std::unique_ptr ast_crate = parser.parse_crate (); + + // handle crate name + handle_crate_name (*ast_crate.get ()); + + // dump options + if (options.dump_option_enabled (CompileOptions::LEXER_DUMP)) + { + dump_lex (parser); + } + if (options.dump_option_enabled (CompileOptions::PARSER_AST_DUMP)) + { + dump_ast (parser, *ast_crate.get ()); + } + if (options.dump_option_enabled (CompileOptions::AST_DUMP_PRETTY)) + { + dump_ast_pretty (*ast_crate.get ()); + } + if (options.dump_option_enabled (CompileOptions::TARGET_OPTION_DUMP)) + { + options.target_data.dump_target_options (); + } + + if (saw_errors ()) + return; + + // setup the mappings for this AST + CrateNum current_crate = mappings->get_current_crate (); + AST::Crate &parsed_crate + = mappings->insert_ast_crate (std::move (ast_crate), current_crate); + + /* basic pipeline: + * - lex + * - parse + * - register plugins (dummy stage for now) - attribute injection? what is + * this? (attribute injection is injecting attributes specified in command + * line into crate root) + * - injection (some lint checks or dummy, register builtin macros, crate + * injection) + * - expansion (expands all macros, maybe build test harness, AST + * validation, maybe macro crate) + * - resolution (name resolution, type resolution, maybe feature checking, + * maybe buffered lints) + * TODO not done */ + + rust_debug ("\033[0;31mSUCCESSFULLY PARSED CRATE \033[0m"); + + // If -fsyntax-only was passed, we can just skip the remaining passes. + // Parsing errors are already emitted in `parse_crate()` + if (flag_syntax_only) + return; + + // register plugins pipeline stage + register_plugins (parsed_crate); + rust_debug ("\033[0;31mSUCCESSFULLY REGISTERED PLUGINS \033[0m"); + if (options.dump_option_enabled (CompileOptions::REGISTER_PLUGINS_DUMP)) + { + // TODO: what do I dump here? + } + + // injection pipeline stage + injection (parsed_crate); + rust_debug ("\033[0;31mSUCCESSFULLY FINISHED INJECTION \033[0m"); + if (options.dump_option_enabled (CompileOptions::INJECTION_DUMP)) + { + // TODO: what do I dump here? injected crate names? + } + + Analysis::AttributeChecker ().go (parsed_crate); + + // expansion pipeline stage + expansion (parsed_crate); + rust_debug ("\033[0;31mSUCCESSFULLY FINISHED EXPANSION \033[0m"); + if (options.dump_option_enabled (CompileOptions::EXPANSION_DUMP)) + { + // dump AST with expanded stuff + rust_debug ("BEGIN POST-EXPANSION AST DUMP"); + dump_ast_expanded (parser, parsed_crate); + rust_debug ("END POST-EXPANSION AST DUMP"); + } + + // resolution pipeline stage + Resolver::NameResolution::Resolve (parsed_crate); + if (options.dump_option_enabled (CompileOptions::RESOLUTION_DUMP)) + { + // TODO: what do I dump here? resolved names? AST with resolved names? + } + + if (saw_errors ()) + return; + + // lower AST to HIR + std::unique_ptr lowered + = HIR::ASTLowering::Resolve (parsed_crate); + if (saw_errors ()) + return; + + // add the mappings to it + HIR::Crate &hir = mappings->insert_hir_crate (std::move (lowered)); + if (options.dump_option_enabled (CompileOptions::HIR_DUMP)) + { + dump_hir (hir); + } + if (options.dump_option_enabled (CompileOptions::HIR_DUMP_PRETTY)) + { + dump_hir_pretty (hir); + } + + // type resolve + Resolver::TypeResolution::Resolve (hir); + if (options.dump_option_enabled (CompileOptions::TYPE_RESOLUTION_DUMP)) + { + dump_type_resolution (hir); + } + + if (saw_errors ()) + return; + + // Various HIR error passes. The privacy pass happens before the unsafe checks + Privacy::Resolver::resolve (hir); + if (saw_errors ()) + return; + + HIR::UnsafeChecker ().go (hir); + HIR::ConstChecker ().go (hir); + + if (saw_errors ()) + return; + + // do compile to gcc generic + Compile::Context ctx (backend); + Compile::CompileCrate::Compile (hir, &ctx); + + // we can't do static analysis if there are errors to worry about + if (!saw_errors ()) + { + // lints + Analysis::ScanDeadcode::Scan (hir); + Analysis::UnusedVariables::Lint (ctx); + + // metadata + bool specified_emit_metadata + = flag_rust_embed_metadata || options.metadata_output_path_set (); + if (!specified_emit_metadata) + { + Metadata::PublicInterface::ExportTo ( + hir, Metadata::PublicInterface::expected_metadata_filename ()); + } + else + { + if (flag_rust_embed_metadata) + Metadata::PublicInterface::Export (hir); + if (options.metadata_output_path_set ()) + Metadata::PublicInterface::ExportTo ( + hir, options.get_metadata_output ()); + } + } + + // pass to GCC middle-end + ctx.write_to_backend (); +} + +void +Session::register_plugins (AST::Crate &crate ATTRIBUTE_UNUSED) +{ + rust_debug ("ran register_plugins (with no body)"); +} + +// TODO: move somewhere else +bool +contains_name (const AST::AttrVec &attrs, std::string name) +{ + for (const auto &attr : attrs) + { + if (attr.get_path () == name) + return true; + } + + return false; +} + +void +Session::injection (AST::Crate &crate) +{ + rust_debug ("started injection"); + + // lint checks in future maybe? + + // register builtin macros + /* In rustc, builtin macros are divided into 3 categories depending on use - + * "bang" macros, "attr" macros, and "derive" macros. I think the meanings + * of these categories should be fairly obvious to anyone who has used rust. + * Builtin macro list by category: Bang + * - asm + * - assert + * - cfg + * - column + * - compile_error + * - concat_idents + * - concat + * - env + * - file + * - format_args_nl + * - format_args + * - global_asm + * - include_bytes + * - include_str + * - include + * - line + * - log_syntax + * - module_path + * - option_env + * - stringify + * - trace_macros + * Attr + * - bench + * - global_allocator + * - test + * - test_case + * Derive + * - Clone + * - Copy + * - Debug + * - Default + * - Eq + * - Hash + * - Ord + * - PartialEq + * - PartialOrd + * - RustcDecodable + * - RustcEncodable + * rustc also has a "quote" macro that is defined differently and is + * supposedly not stable so eh. */ + /* TODO: actually implement injection of these macros. In particular, derive + * macros, cfg, and test should be prioritised since they seem to be used + * the most. */ + + // crate injection + std::vector names; + if (contains_name (crate.inner_attrs, "no_core")) + { + // no prelude + injected_crate_name = ""; + } + else if (contains_name (crate.inner_attrs, "no_std")) + { + names.push_back ("core"); + + if (!contains_name (crate.inner_attrs, "compiler_builtins")) + { + names.push_back ("compiler_builtins"); + } + + injected_crate_name = "core"; + } + else + { + names.push_back ("std"); + + injected_crate_name = "std"; + } + + // reverse iterate through names to insert crate items in "forward" order at + // beginning of crate + for (auto it = names.rbegin (); it != names.rend (); ++it) + { + // create "macro use" attribute for use on extern crate item to enable + // loading macros from it + AST::Attribute attr (AST::SimplePath::from_str ("macro_use", Location ()), + nullptr); + + // create "extern crate" item with the name + std::unique_ptr extern_crate ( + new AST::ExternCrate (*it, AST::Visibility::create_error (), + {std::move (attr)}, + Linemap::unknown_location ())); + + // insert at beginning + // crate.items.insert (crate.items.begin (), std::move (extern_crate)); + } + + // create use tree path + // prelude is injected_crate_name + // FIXME: Once we do want to include the standard library, add the prelude + // use item + // std::vector segments + // = {AST::SimplePathSegment (injected_crate_name, Location ()), + // AST::SimplePathSegment ("prelude", Location ()), + // AST::SimplePathSegment ("v1", Location ())}; + // // create use tree and decl + // std::unique_ptr use_tree ( + // new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED, + // AST::SimplePath (std::move (segments)), Location ())); + // AST::Attribute prelude_attr (AST::SimplePath::from_str ("prelude_import", + // Location ()), + // nullptr); + // std::unique_ptr use_decl ( + // new AST::UseDeclaration (std::move (use_tree), + // AST::Visibility::create_error (), + // {std::move (prelude_attr)}, Location ())); + + // crate.items.insert (crate.items.begin (), std::move (use_decl)); + + /* TODO: potentially add checking attribute crate type? I can't figure out + * what this does currently comment says "Unconditionally collect crate + * types from attributes to make them used", which presumably refers to + * checking the linkage info by "crate_type". It also seems to ensure that + * an invalid crate type is not specified, so maybe just do that. Valid + * crate types: bin lib dylib staticlib cdylib rlib proc-macro */ + + // this crate type will have options affecting the metadata ouput + + rust_debug ("finished injection"); +} + +void +Session::expansion (AST::Crate &crate) +{ + rust_debug ("started expansion"); + + /* rustc has a modification to windows PATH temporarily here, which may end + * up being required */ + + // create macro expansion config? + // if not, would at least have to configure recursion_limit + ExpansionCfg cfg; + + // create extctxt? from parse session, cfg, and resolver? + /* expand by calling cxtctxt object's monotonic_expander's expand_crate + * method. */ + MacroExpander expander (crate, cfg, *this); + expander.expand_crate (); + + // error reporting - check unused macros, get missing fragment specifiers + + // build test harness + + // ast validation (also with proc macro decls) + + // maybe create macro crate if not rustdoc + + rust_debug ("finished expansion"); +} + +void +Session::dump_lex (Parser &parser) const +{ + std::ofstream out; + out.open (kLexDumpFile); + if (out.fail ()) + { + rust_error_at (Linemap::unknown_location (), "cannot open %s:%m; ignored", + kLexDumpFile); + return; + } + + // TODO: rewrite lexer dump or something so that it allows for the crate + // to already be parsed + parser.debug_dump_lex_output (out); + out.close (); +} + +void +Session::dump_ast (Parser &parser, AST::Crate &crate) const +{ + std::ofstream out; + out.open (kASTDumpFile); + if (out.fail ()) + { + rust_error_at (Linemap::unknown_location (), "cannot open %s:%m; ignored", + kASTDumpFile); + return; + } + + parser.debug_dump_ast_output (crate, out); + out.close (); +} + +void +Session::dump_ast_pretty (AST::Crate &crate) const +{ + std::ofstream out; + out.open (kASTPrettyDumpFile); + if (out.fail ()) + { + rust_error_at (Linemap::unknown_location (), "cannot open %s:%m; ignored", + kASTDumpFile); + return; + } + + AST::Dump (out).go (crate); + + out.close (); +} + +void +Session::dump_ast_expanded (Parser &parser, AST::Crate &crate) const +{ + std::ofstream out; + out.open (kASTExpandedDumpFile); + if (out.fail ()) + { + rust_error_at (Linemap::unknown_location (), "cannot open %s:%m; ignored", + kASTExpandedDumpFile); + return; + } + + parser.debug_dump_ast_output (crate, out); + out.close (); +} + +void +Session::dump_hir (HIR::Crate &crate) const +{ + std::ofstream out; + out.open (kHIRDumpFile); + if (out.fail ()) + { + rust_error_at (Linemap::unknown_location (), "cannot open %s:%m; ignored", + kHIRDumpFile); + return; + } + + out << crate.as_string (); + out.close (); +} + +void +Session::dump_hir_pretty (HIR::Crate &crate) const +{ + std::ofstream out; + out.open (kHIRPrettyDumpFile); + if (out.fail ()) + { + rust_error_at (Linemap::unknown_location (), "cannot open %s:%m; ignored", + kHIRPrettyDumpFile); + return; + } + + HIR::Dump (out).go (crate); + out.close (); +} + +void +Session::dump_type_resolution (HIR::Crate &hir) const +{ + std::ofstream out; + out.open (kHIRTypeResolutionDumpFile); + if (out.fail ()) + { + rust_error_at (Linemap::unknown_location (), "cannot open %s:%m; ignored", + kHIRTypeResolutionDumpFile); + return; + } + + Resolver::TypeResolverDump::go (hir, out); + out.close (); +} + +// imports + +NodeId +Session::load_extern_crate (const std::string &crate_name, Location locus) +{ + // has it already been loaded? + CrateNum found_crate_num = UNKNOWN_CREATENUM; + bool found = mappings->lookup_crate_name (crate_name, found_crate_num); + if (found) + { + NodeId resolved_node_id = UNKNOWN_NODEID; + bool resolved + = mappings->crate_num_to_nodeid (found_crate_num, resolved_node_id); + rust_assert (resolved); + + return resolved_node_id; + } + + std::string relative_import_path = ""; + Import::Stream *s + = Import::open_package (crate_name, locus, relative_import_path); + if (s == NULL) + { + rust_error_at (locus, "failed to locate crate %<%s%>", + crate_name.c_str ()); + return UNKNOWN_NODEID; + } + + Imports::ExternCrate extern_crate (*s); + bool ok = extern_crate.load (locus); + if (!ok) + { + rust_error_at (locus, "failed to load crate metadata"); + return UNKNOWN_NODEID; + } + + // ensure the current vs this crate name don't collide + const std::string current_crate_name = mappings->get_current_crate_name (); + if (current_crate_name.compare (extern_crate.get_crate_name ()) == 0) + { + rust_error_at (locus, "current crate name %<%s%> collides with this", + current_crate_name.c_str ()); + return UNKNOWN_NODEID; + } + + // setup mappings + CrateNum saved_crate_num = mappings->get_current_crate (); + CrateNum crate_num + = mappings->get_next_crate_num (extern_crate.get_crate_name ()); + mappings->set_current_crate (crate_num); + + // then lets parse this as a 2nd crate + Lexer lex (extern_crate.get_metadata ()); + Parser parser (lex); + std::unique_ptr metadata_crate = parser.parse_crate (); + AST::Crate &parsed_crate + = mappings->insert_ast_crate (std::move (metadata_crate), crate_num); + + // name resolve it + Resolver::NameResolution::Resolve (parsed_crate); + + // perform hir lowering + std::unique_ptr lowered + = HIR::ASTLowering::Resolve (parsed_crate); + HIR::Crate &hir = mappings->insert_hir_crate (std::move (lowered)); + + // perform type resolution + Resolver::TypeResolution::Resolve (hir); + + // always restore the crate_num + mappings->set_current_crate (saved_crate_num); + + return parsed_crate.get_node_id (); +} +// + +void +TargetOptions::dump_target_options () const +{ + std::ofstream out; + out.open (kTargetOptionsDumpFile); + if (out.fail ()) + { + rust_error_at (Linemap::unknown_location (), "cannot open %s:%m; ignored", + kTargetOptionsDumpFile); + return; + } + + if (features.empty ()) + { + out << "No target options available!\n"; + } + + for (const auto &pairs : features) + { + for (const auto &value : pairs.second) + out << pairs.first + ": \"" + value + "\"\n"; + + if (pairs.second.empty ()) + out << pairs.first + "\n"; + } + + out.close (); +} + +void +TargetOptions::init_derived_values () +{ + // enable derived values based on target families + if (has_key_value_pair ("target_family", "unix")) + insert_key ("unix"); + if (has_key_value_pair ("target_family", "windows")) + insert_key ("windows"); + + // implicitly enable features - this should not be required in general + if (has_key_value_pair ("target_feature", "aes")) + enable_implicit_feature_reqs ("aes"); + if (has_key_value_pair ("target_feature", "avx")) + enable_implicit_feature_reqs ("sse4.2"); + if (has_key_value_pair ("target_feature", "avx2")) + enable_implicit_feature_reqs ("avx"); + if (has_key_value_pair ("target_feature", "pclmulqdq")) + enable_implicit_feature_reqs ("sse2"); + if (has_key_value_pair ("target_feature", "sha")) + enable_implicit_feature_reqs ("sse2"); + if (has_key_value_pair ("target_feature", "sse2")) + enable_implicit_feature_reqs ("sse"); + if (has_key_value_pair ("target_feature", "sse3")) + enable_implicit_feature_reqs ("sse2"); + if (has_key_value_pair ("target_feature", "sse4.1")) + enable_implicit_feature_reqs ("sse3"); + if (has_key_value_pair ("target_feature", "sse4.2")) + enable_implicit_feature_reqs ("sse4.1"); + if (has_key_value_pair ("target_feature", "ssse3")) + enable_implicit_feature_reqs ("sse3"); +} + +void +TargetOptions::enable_implicit_feature_reqs (std::string feature) +{ + if (feature == "aes") + enable_implicit_feature_reqs ("sse2"); + else if (feature == "avx") + enable_implicit_feature_reqs ("sse4.2"); + else if (feature == "avx2") + enable_implicit_feature_reqs ("avx"); + else if (feature == "fma") + enable_implicit_feature_reqs ("avx"); + else if (feature == "pclmulqdq") + enable_implicit_feature_reqs ("sse2"); + else if (feature == "sha") + enable_implicit_feature_reqs ("sse2"); + else if (feature == "sse2") + enable_implicit_feature_reqs ("sse"); + else if (feature == "sse3") + enable_implicit_feature_reqs ("sse2"); + else if (feature == "sse4.1") + enable_implicit_feature_reqs ("sse3"); + else if (feature == "sse4.2") + enable_implicit_feature_reqs ("sse4.1"); + else if (feature == "ssse3") + enable_implicit_feature_reqs ("sse3"); + + if (!has_key_value_pair ("target_feature", feature)) + { + insert_key_value_pair ("target_feature", feature); + + rust_debug ("had to implicitly enable feature '%s'!", feature.c_str ()); + } +} + +// NOTEs: +/* mrustc compile pipeline: + * - target load (pass target spec to parser?) + * - parse (convert source to AST) + * - load crates (load any explicitly mentioned extern crates [not all of + * them]) + * - expand (AST transformations from attributes and macros, loads remaining + * extern crates [std/core and any triggered by macro expansion]) + * - implicit crates (test harness, allocator crate, panic crate) + * - resolve use (annotate every 'use' item with source [supposedly handles + * nasty recursion]) + * - resolve index (generate index of visible items for every module [avoids + * recursion in next pass]) + * - resolve absolute (resolve all paths into either variable names + * [types/values] or absolute paths) + * - HIR lower (convert modified AST to simpler HIR [both expressions and + * module tree]) + * - resolve type aliases (replace any usages of type aliases with actual + * type [except associated types]) + * - resolve bind (iterate HIR tree and set binding annotations on all + * concrete types [avoids path lookups later]) + * - resolve HIR markings (generate "markings" [e.g. for Copy/Send/Sync/...] + * for all types + * - sort impls (small pass - sort impls into groups) + * - resolve UFCS outer (determine source trait for all top-level ::Type + * [qualified] paths) + * - resolve UFCS paths (do the same, but include for exprs this time. also + * normalises results of previous pass [expanding known associated types]) + * - constant evaluate (evaluate all constants) + * - typecheck outer (checks impls are sane) + * - typecheck expressions (resolve and check types for all exprs) + * - expand HIR annotate (annotate how exprs are used - used for closure + * extractions and reborrows) + * - expand HIR closures (extract closures into structs implementing Fn* + * traits) + * - expand HIR vtables (generate vtables for types with dyn dispatch) + * - expand HIR calls (converts method and callable calls into explicit + * function calls) + * - expand HIR reborrows (apply reborrow rules [taking '&mut *v' instead of + * 'v']) + * - expand HIR erasedtype (replace all erased types 'impl Trait' with the + * true type) + * - typecheck expressions (validate - double check that previous passes + * haven't broke type system rules) + * - lower MIR (convert HIR exprs into a control-flow graph [MIR]) + * - MIR validate (check that the generated MIR is consistent) + * - MIR cleanup (perform various transformations on MIR - replace reads of + * const items with the item itself; convert casts to unsized types into + * 'MakeDst' operations) + * - MIR optimise (perform various simple optimisations on the MIR - constant + * propagation, dead code elimination, borrow elimination, some inlining) + * - MIR validate PO (re-validate the MIR) + * - MIR validate full (optionally: perform expensive state-tracking + * validation on MIR) + * - trans enumerate (enumerate all items needed for code generation, + * primarily types used for generics) + * - trans auto impls (create magic trait impls as enumerated in previous + * pass) + * - trans monomorph (generate monomorphised copies of all functions [with + * generics replaced with real types]) + * - MIR optimise inline (run optimisation again, this time with full type + * info [primarily for inlining]) + * - HIR serialise (write out HIR dump [module tree and generic/inline MIR]) + * - trans codegen (generate final output file: emit C source file and call C + * compiler) */ + +/* rustc compile pipeline (basic, in way less detail): + * - parse input (parse .rs to AST) + * - name resolution, macro expansion, and configuration (process AST + * recursively, resolving paths, expanding macros, processing #[cfg] nodes + * [i.e. maybe stripping stuff from AST]) + * - lower to HIR + * - type check and other analyses (e.g. privacy checking) + * - lower to MIR and post-processing (and do stuff like borrow checking) + * - translation to LLVM IR and LLVM optimisations (produce the .o files) + * - linking (link together .o files) */ + +/* Pierced-together rustc compile pipeline (from source): + * - parse input (parse file to crate) + * - register plugins (attributes injection, set various options, register + * lints, load plugins) + * - expansion/configure and expand (initial 'cfg' processing, 'loading + * compiler plugins', syntax expansion, secondary 'cfg' expansion, synthesis + * of a test harness if required, injection of any std lib dependency and + * prelude, and name resolution) - actually documented inline + * - seeming pierced-together order: pre-AST expansion lint checks, + * registering builtin macros, crate injection, then expand all macros, then + * maybe build test harness, AST validation, maybe create a macro crate (if + * not rustdoc), name resolution, complete gated feature checking, add all + * buffered lints + * - create global context (lower to HIR) + * - analysis on global context (HIR optimisations? create MIR?) + * - code generation + * - link */ +} // namespace Rust + +#if CHECKING_P +namespace selftest { +void +rust_crate_name_validation_test (void) +{ + auto error = Rust::Error (Location (), std::string ()); + ASSERT_TRUE (Rust::validate_crate_name ("example", error)); + ASSERT_TRUE (Rust::validate_crate_name ("abcdefg_1234", error)); + ASSERT_TRUE (Rust::validate_crate_name ("1", error)); + // FIXME: The next test does not pass as of current implementation + // ASSERT_TRUE (Rust::CompileOptions::validate_crate_name ("惊吓")); + // NOTE: - is not allowed in the crate name ... + + ASSERT_FALSE (Rust::validate_crate_name ("abcdefg-1234", error)); + ASSERT_FALSE (Rust::validate_crate_name ("a+b", error)); + ASSERT_FALSE (Rust::validate_crate_name ("/a+b/", error)); + + /* Tests for crate name inference */ + ASSERT_EQ (Rust::infer_crate_name ("c.rs"), "c"); + // NOTE: ... but - is allowed when in the filename + ASSERT_EQ (Rust::infer_crate_name ("a-b.rs"), "a_b"); + ASSERT_EQ (Rust::infer_crate_name ("book.rs.txt"), "book.rs"); +#if defined(HAVE_DOS_BASED_FILE_SYSTEM) + ASSERT_EQ (Rust::infer_crate_name ("a\\c\\a-b.rs"), "a_b"); +#else + ASSERT_EQ (Rust::infer_crate_name ("a/c/a-b.rs"), "a_b"); +#endif +} +} // namespace selftest +#endif // CHECKING_P diff --git a/gcc/rust/rust-session-manager.h b/gcc/rust/rust-session-manager.h new file mode 100644 index 00000000000..99dd107239b --- /dev/null +++ b/gcc/rust/rust-session-manager.h @@ -0,0 +1,358 @@ +// 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 +// . +// #include "rust-session-manager.h" + +#ifndef RUST_SESSION_MANAGER_H +#define RUST_SESSION_MANAGER_H + +#include "rust-linemap.h" +#include "rust-backend.h" +#include "rust-hir-map.h" +#include "safe-ctype.h" + +#include "config.h" +#include "rust-system.h" +#include "coretypes.h" +#include "options.h" + +namespace Rust { +// parser forward decl +template class Parser; +class Lexer; +// crate forward decl +namespace AST { +struct Crate; +} +// crate forward decl +namespace HIR { +struct Crate; +} + +/* Data related to target, most useful for conditional compilation and + * whatever. */ +struct TargetOptions +{ + /* TODO: maybe make private and access through helpers to allow changes to + * impl */ + std::unordered_map > features; + +public: + // Returns whether a key is defined in the feature set. + bool has_key (std::string key) const + { + return features.find (key) != features.end (); + } + + // Returns whether a key exists with the given value in the feature set. + bool has_key_value_pair (std::string key, std::string value) const + { + auto it = features.find (key); + if (it != features.end ()) + { + auto set = it->second; + auto it2 = set.find (value); + if (it2 != set.end ()) + return true; + } + return false; + } + + /* Returns the singular value from the key, or if the key has multiple, an + * empty string. */ + std::string get_singular_value (std::string key) const + { + auto it = features.find (key); + if (it != features.end ()) + { + auto set = it->second; + if (set.size () == 1) + return *set.begin (); + } + return ""; + } + + /* Returns all values associated with a key (including none), or an empty + * set if no key is found. */ + std::unordered_set get_values_for_key (std::string key) const + { + auto it = features.find (key); + if (it != features.end ()) + return it->second; + return {}; + } + + /* Inserts a key (no value) into the feature set. This will do nothing if + * the key already exists. This returns whether the insertion was successful + * (i.e. whether key already existed). */ + bool insert_key (std::string key) + { + return features + .insert (std::make_pair (key, std::unordered_set ())) + .second; + } + + // Inserts a key-value pair into the feature set. + void insert_key_value_pair (std::string key, std::string value) + { + auto existing_set = get_values_for_key (key); + existing_set.insert (std::move (value)); + features[std::move (key)] = std::move (existing_set); + } + + // Dump all target options to stderr. + void dump_target_options () const; + + /* Creates derived values and implicit enables after all target info is + * added (e.g. "unix"). */ + void init_derived_values (); + + /* Enables all requirements for the feature given, and will enable feature + * itself if not enabled. */ + void enable_implicit_feature_reqs (std::string feature); + + /* According to reference, Rust uses either multi-map key-values or just + * values (although values may be aliases for a key-value value). This seems + * like overkill. Thus, depending on whether the attributes used in cfg are + * fixed or not, I think I'll either put each non-multimap "key-value" as a + * separate field and have the multimap "key-values" in a regular map for + * that one key, or actually use a multimap. + * + * rustc itself uses a set of key-value tuples where the second tuple + * element is optional. This gets rid of the requirement to make a + * multi-map, I guess, but seems like it might make search slow (unless all + * "is defined"-only ones have empty string as second element). */ + /* cfg attributes: + * - target_arch: single value + * - target_feature: multiple values possible + * - target_os: single value + * - target_family: single value (or no value?) + * - unix: set when target_family = "unix" + * - windows: set when target_family = "windows" + * - if these are just syntactic sugar, then maybe have a separate set or + * map for this kind of stuff + * - target_env: set when needed for disambiguation about ABI - usually + * empty string for GNU, complicated + * - seems to be a single value (if any) + * - target_endian: single value; "little" or "big" + * - target_pointer_width: single value, "32" for 32-bit pointers, etc. + * - target_vendor, single value + * - test: set when testing is being done + * - again, seems similar to a "is defined" rather than "is equal to" like + * unix + * - debug_assertions: seems to "is defined" + * - proc_macro: no idea, bad docs. seems to be boolean, so maybe "is + * defined" + */ +}; + +// Defines compiler options (e.g. dump, etc.). +struct CompileOptions +{ + enum DumpOption + { + LEXER_DUMP, + PARSER_AST_DUMP, + AST_DUMP_PRETTY, + REGISTER_PLUGINS_DUMP, + INJECTION_DUMP, + EXPANSION_DUMP, + RESOLUTION_DUMP, + TARGET_OPTION_DUMP, + HIR_DUMP, + HIR_DUMP_PRETTY, + TYPE_RESOLUTION_DUMP, + }; + + std::set dump_options; + + /* configuration options - actually useful for conditional compilation and + * whatever data related to target arch, features, os, family, env, endian, + * pointer width, vendor */ + TargetOptions target_data; + std::string crate_name; + bool crate_name_set_manually = false; + bool enable_test = false; + bool debug_assertions = false; + bool proc_macro = false; + std::string metadata_output_path; + + enum class Edition + { + E2015 = 0, + E2018, + E2021, + } edition + = Edition::E2015; + + bool dump_option_enabled (DumpOption option) const + { + return dump_options.find (option) != dump_options.end (); + } + + void enable_dump_option (DumpOption option) { dump_options.insert (option); } + + void enable_all_dump_options () + { + enable_dump_option (DumpOption::LEXER_DUMP); + enable_dump_option (DumpOption::PARSER_AST_DUMP); + enable_dump_option (DumpOption::AST_DUMP_PRETTY); + enable_dump_option (DumpOption::REGISTER_PLUGINS_DUMP); + enable_dump_option (DumpOption::INJECTION_DUMP); + enable_dump_option (DumpOption::EXPANSION_DUMP); + enable_dump_option (DumpOption::RESOLUTION_DUMP); + enable_dump_option (DumpOption::TARGET_OPTION_DUMP); + enable_dump_option (DumpOption::HIR_DUMP); + enable_dump_option (DumpOption::HIR_DUMP_PRETTY); + enable_dump_option (DumpOption::TYPE_RESOLUTION_DUMP); + } + + void set_crate_name (std::string name) + { + rust_assert (!name.empty ()); + + crate_name = std::move (name); + } + + const std::string &get_crate_name () const + { + rust_assert (!crate_name.empty ()); + return crate_name; + } + + void set_edition (int raw_edition) + { + edition = static_cast (raw_edition); + } + + const Edition &get_edition () { return edition; } + + void set_metadata_output (const std::string &path) + { + metadata_output_path = path; + } + + const std::string &get_metadata_output () const + { + return metadata_output_path; + } + + bool metadata_output_path_set () const + { + return !metadata_output_path.empty (); + } +}; + +/* Defines a compiler session. This is for a single compiler invocation, so + * potentially includes parsing multiple crates. */ +struct Session +{ + CompileOptions options; + /* This should really be in a per-crate storage area but it is wiped with + * every file so eh. */ + std::string injected_crate_name; + + /* extra files get included during late stages of compilation (e.g. macro + * expansion) */ + std::vector extra_files; + + // backend wrapper to GCC GENERIC + Backend *backend; + + // backend linemap + Linemap *linemap; + + // mappings + Analysis::Mappings *mappings; + +public: + /* Get a reference to the static session instance */ + static Session &get_instance (); + + Session () = default; + ~Session () = default; + + /* This initializes the compiler session. Corresponds to langhook + * grs_langhook_init(). Note that this is called after option handling. */ + void init (); + + // delete those constructors so we don't access the singleton in any + // other way than via `get_instance()` + Session (Session const &) = delete; + void operator= (Session const &) = delete; + + bool handle_option (enum opt_code code, const char *arg, HOST_WIDE_INT value, + int kind, location_t loc, + const struct cl_option_handlers *handlers); + void handle_input_files (int num_files, const char **files); + void init_options (); + void handle_crate_name (const AST::Crate &parsed_crate); + + /* This function saves the filename data into the session manager using the + * `move` semantics, and returns a C-style string referencing the input + * std::string */ + inline const char *include_extra_file (std::string filename) + { + extra_files.push_back (std::move (filename)); + return extra_files.back ().c_str (); + } + + NodeId load_extern_crate (const std::string &crate_name, Location locus); + +private: + void compile_crate (const char *filename); + bool enable_dump (std::string arg); + + void dump_lex (Parser &parser) const; + void dump_ast (Parser &parser, AST::Crate &crate) const; + void dump_ast_pretty (AST::Crate &crate) const; + void dump_ast_expanded (Parser &parser, AST::Crate &crate) const; + void dump_hir (HIR::Crate &crate) const; + void dump_hir_pretty (HIR::Crate &crate) const; + void dump_type_resolution (HIR::Crate &crate) const; + + // pipeline stages - TODO maybe move? + /* Register plugins pipeline stage. TODO maybe move to another object? + * Currently dummy stage. In future will handle attribute injection + * (top-level inner attribute creation from command line arguments), setting + * options maybe, registering lints maybe, loading plugins maybe. */ + void register_plugins (AST::Crate &crate); + + /* Injection pipeline stage. TODO maybe move to another object? Maybe have + * some lint checks (in future, obviously), register builtin macros, crate + * injection. */ + void injection (AST::Crate &crate); + + /* Expansion pipeline stage. TODO maybe move to another object? Expands all + * macros, maybe build test harness in future, AST validation, maybe create + * macro crate (if not rustdoc).*/ + void expansion (AST::Crate &crate); + + // handle cfg_option + bool handle_cfg_option (std::string &data); +}; + +} // namespace Rust + +#if CHECKING_P +namespace selftest { +extern void +rust_crate_name_validation_test (void); +} +#endif // CHECKING_P + +#endif From patchwork Wed Aug 24 11:59:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: herron.philip@googlemail.com X-Patchwork-Id: 57008 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 07B58383FBBC for ; Wed, 24 Aug 2022 12:10:00 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) by sourceware.org (Postfix) with ESMTPS id C32B4384D146; Wed, 24 Aug 2022 12:01:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C32B4384D146 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=googlemail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=googlemail.com Received: by mail-wm1-x32c.google.com with SMTP id bd26-20020a05600c1f1a00b003a5e82a6474so712632wmb.4; Wed, 24 Aug 2022 05:01:29 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc; bh=A6em8wi6U7ZPMjRGujJlPRLgLsHxNdvOC2gWpoiDVOs=; b=I02JoSwNuVq8E2rfLJdcNMNrYfarW7q80LA9ls+uLmYd50yQitQ3YZapNCJZXruSyf 0/NVOxDj+DkkpwFn4StupraIAi+KQoHpCM4U7O//7BdrbPYU671J+IaUeHEe3LxVzxxY 6WWL28swZBs23ScEHKV5dJnytl9E1uAZ6+vmdEDGNffaSwTbBfoQafRKhTqFYGoi2iMX 2GwXSTWRuAMESMuMkQ8oddc/p2FSlRvbXCX3HAItGpHY0oKqISvcTzbQwEhv362Gl6cJ bYKZ479SxjQFhq0TVeJ+3RlMyl3gx8RQZCbyBtW1bE2obmFlqEkO6fnBW8XyECdOMJWy 1+Ow== 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; bh=A6em8wi6U7ZPMjRGujJlPRLgLsHxNdvOC2gWpoiDVOs=; b=CcxpGqXoHpBoY2B0c5Z6ctxaGlXymeX8C4qGJ6vCUXBz3ISsnq2YjIJtI7K4Hdo8Un 4nLp48N0WrfbVENSx81gYTRwiEOtgyMIUrlCQ7JQ4mVCsnUcYEgnBYTlx62SCL5vMOR6 AO9lQMKQHhhWGRgaQF8kvlAtYhjXWcSl/1GMNEswCQK7PIQ1VXtDkT8uta8HtWP8NH2w h6VJfV0lizuOMMcbjXQZfz69FbxqhCy3bywZrhWyObvWhBhWDMmV4XdQADbMcZ2/R40R /u0P2R+RHWjTgxjlpgwhaMVealBuP7wYun3kRnNoLg56I8Hsq6iAttdOMi6ea4MEChD2 8J1Q== X-Gm-Message-State: ACgBeo1evXZwIm3kt+dMOTi+onXD31pQXzRMV5HFnJm+M9Otr5XYPfVF MRpoceDJnuJplCTFz2wvuyLoRqMm320= X-Google-Smtp-Source: AA6agR7sw5qn8znW7004hg2WzOoTOViXqbD+gZF9SRkOcjqCvwkB2kOA+Nk4OAxrO5MeAUiyGV02hQ== X-Received: by 2002:a05:600c:4fc2:b0:3a5:c491:5ee1 with SMTP id o2-20020a05600c4fc200b003a5c4915ee1mr4903862wmq.62.1661342485529; Wed, 24 Aug 2022 05:01:25 -0700 (PDT) Received: from localhost.localdomain ([86.14.124.218]) by smtp.gmail.com with ESMTPSA id cc19-20020a5d5c13000000b0022571d43d32sm1697676wrb.21.2022.08.24.05.01.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Aug 2022 05:01:24 -0700 (PDT) From: herron.philip@googlemail.com X-Google-Original-From: philip.herron@embecosm.com To: gcc-patches@gcc.gnu.org Subject: [PATCH Rust front-end v2 37/37] gccrs: Add README, CONTRIBUTING and compiler logo Date: Wed, 24 Aug 2022 12:59:56 +0100 Message-Id: <20220824115956.737931-38-philip.herron@embecosm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220824115956.737931-1-philip.herron@embecosm.com> References: <20220824115956.737931-1-philip.herron@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-8.3 required=5.0 tests=BAYES_50, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, LOTS_OF_MONEY, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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: philip.herron@embecosm.com Cc: gcc-rust@gcc.gnu.org, Philip Herron Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron We still need to write out documentation section but these README's will help in the mean time. --- gcc/rust/CONTRIBUTING.md | 130 +++++++++++++++++++ gcc/rust/README.md | 264 +++++++++++++++++++++++++++++++++++++++ gcc/rust/logo.png | Bin 0 -> 70864 bytes 3 files changed, 394 insertions(+) create mode 100644 gcc/rust/CONTRIBUTING.md create mode 100644 gcc/rust/README.md create mode 100644 gcc/rust/logo.png GIT binary patch literal 70864 zcmeFYWmH|w(k_a-yR(o4cXxLU5CQ~WXmEGe;O_1T?j9hxy9W2*?s8U=cklh~d%pXf z`;BqWzYPP%nmwzZu70|zx~t|~pOqD*kP!$Fz`($eWu(Pbz`!8)!N9<;;9x*471Xc{ zU|_h9?rIv2Dh4h9TYDQ5b4z1@qnoWUz}VH?1Psh|sXWcxo}v{!@O2AI5MmC(mZ%K< zn_u)PQ+fh>erjV+ZDEY`yHRVf#6-ljlc&A4`RDLT!xe4D`g60a%4LV>0IJcBZ@ZU# zcTZ2=-xM!@J|8Gmwx+KsQAG1@JEfeSd)0Iw@}r)1JU)_dY~4j;dhx>tnC={s0^9Vm zg*pV+s3MLZKd(|qZ#Wrutl79`Q}^D6UL2lYlf+)D`=l-Dp3?cqS9?8gtL0-Oa$NFB z>6JQVHSRkY3pB#Ge>fWdJY*pvq<44sxHU15vMEF6=G~8_moHzL-E|nd#`31$kL=Bh z^k7!P5P>F9$~wmv8J<9(1H zw}{lbYKr@mb$$FjlH{p~>N7%;X(}Nm5ok?Vvs&4XAKrS0;sWSK+L=$G_@p@^pG$6rRsO=!Y59;qYj z%|&eDJpHo4!!+~>t5b?5$K+Yb zmtC!|vsxdIo$6-n=|;7z%C9-yj|N4i3#X&ouUGrm^8(mVR|U8YBk)br+>*>|$2cE} z5bw&`hHBn__~;c$>|&oTx!Q1O-Fj;G9bA?w+x}=~T2W{VqCVaF+s;yXFnzJ z=jKmqbhmr&5l_GN7Ap^)mwKy5CR;pnOQ2<9%|?Xv5|y~VhX!+08}&rwk$P`E#euSt zODAiTAkn)hf}QVwAE;q{SGMwD$NM8!@(-b}AD?u2il?51X!q1wY!V;qtvkLfCE=A7 z8!F+pn7;GMd*)uRL;n#I;Vo$0>dlsIcSviHA)sW+vX@!vQ2&j)x{zp@@mSGE$;u$x zEx5y5`&y~_TXLU$jV{q>+M3tUn6~~k9$sQltqP%qZT;qjv0;9)vfNSxtrnpR(r&ew z1iR8Q1J0buxC(C>{=*UhBZ>c;cU?!MWzBw2;_h4*q$&7Xyk&1lxV)trX@VtT?^Su0%6%apCc(?Fk4pTN?sxW!7nL~rL< z?weI%9{UwHX@1X~Z#2k#5v7#JbDjWB2L(uklUn<}(?6=ud73_7ohU}#vhF4Q&6BI6 z&sFpu3$f$`#25wZfyv$s#3#?=E7hZ!Y>7P6XPJtXwxUd@N+hw2+Po#VsHE@}wA=MH zgD#>O`~ij*L3=pe+g+A}Ym4;p#%6?B*SAK8lGwXhh{TCsFauVRz0}eMlhYNHM@%bG zR_Yrd&OSsZA=fskSPywr4!59;eTvrX*rV^sen0ZCAdcQA)TRc=fiO3j4?2^4|F zRXF;tohPNijV#;>YYD4Q_5-r`3OX69++T=qH{OE2UXFJohk+|a(HGv-8MZ)ssg)2& zZT6&#>Cd(bRq5`Q_&zt4bsv4d%JEagPHc;%868PJf)^h*Cb`XoPw)aQ$4?i0vtidw z{Cej69$pjPdR5qT^$$hq(@mA8L-6v4O4<+jxzwj+uZ!Vu?DJgtm>m6pl#QqQG|$aas%+g}DpR#jWT zZEXQh=~f~%p&<4ZH9&c<-#k9Dxe(LZW&hDf!7nq>A8kIB8GSDHjSw<9go>hN0LB7K z6Gtxc$kQgVX;{NnXz6yHd%IVG6YT;%iGLZa!?a!k`YBR=>x?|kXGVEb#$n$Emg@$Z zpE<`7s>FSY*~`*O5wVmi+9*Vh`hyYujL^c?j4=9u?DSZ0ZH9SyhwOkR&h(zQUwzAp z@HIDsOuAOE(ccW^5;#yj`5sc#=@>K;@?2BXQ52_2f>rOi1{0q|P490yjbr_c2v;GO zYGAUFk%rH)&tnJ+ioRCDk}0vq=S^Miq0&Ny+>JUY=KpDspE2s zXvF6B*R4goqkJ^ss&=_q#E zI#_!Q0w+H}Z!s5MquwD*DmsL)A8ltDcbH+Tn{vJDejyK~PBECbN^4)&MGs`(gJBX0 z@wXkvbB{8MVg$bEw9_}~bw7EZWzv`8rT6#TqszA@KMq(Y4tCOzdEp_;7`?&gyqV`p z_;LY>NvSPn%Z*v^X7CN*;Q)&#(Lxzush3oUF`IzJanF~g5LE|H)vspedD;sTekoz_v_gqapx4|!nuxoln z4UzGoH9BLbVj)F}cQ#xp=hrOiVMVbk_?tPx_`x;gu*6cRxXKiS*&>CEZI#K8%&a@c zjjU(nD2`>LbZ!~8-FiCmZzpEM_AGhv-@k+^PPnt9$dJsV%5Qx42WllAC`Y~96IiN8 zk51gmstO@}^XU^^MP^aEiixUGD-*c=G{XeGCQL;oWVkpav?D?vj#?+##epo**~{(| zH5LxlG)uu-3`{8DimoyKmpI1BQiH8-J9TsW(-8$jTo^ zT@wK448WTyjPG)kG0VkBgxm6vzGpBW$$fh0?NxiTHpk7YMw%EfhtC}`!xJarFUxrA zP}iKcW6ql1e!-^;l`ta!1V&W|CyRxn-dItyvb}B0Ao@R zxA0|*qg(1aiZD?AHB)B?k+Kduz%lFU&~7DP>&-`7XYK%LvMLU$*BP0zk#)W zBswOw56_ysW73pxS4cI1f%HPvyb&UGdoAkwE?1VeXC1RI^U4WN`)G58w&-IGipFsj z`@2_!7;K}X0~iGIHAtfM3sbJ#fVVhN1F*|jscu45hxNm9r zndJ2|zZ}o1yfD%1ic&<^s2vp>gonD&ecz-{4pwMoRYf8-K$i=oNJHb^=GG%SLsR)o zR4!k5)KC>gtojkyxe`OBnL<5(UK4H>BDtcQiPvX51Hf^dnM&tX_KgTzkV^+0Iegs> zrf=I~$9T7S5Mso4Q`&<~fHOZQV5POecttn(si~$-=pEnFcU#A#;I?tYj&Y2XF++`Z z10~`ynTPO;Bt!_-FOYz-8@yYzOoE?oWW+`Z1S6XIdR>Gv`9tBv>tPxkW4CcIoIc82 ze3AznX8iyqCGta*SRNf0K9^Y4Z~JjsR0Nr29Uf>zPkkJ8`!OyN^Dr=A3H^C1)yf0j zD1?arEwt>Mw-b5vaE(Y*nGmKJndV~{PL=$Vj2=08xAPYB4C>l+2nF;Bj+xJ^rTwE+ z5EFZ~$igT#0jfLU4UQf_6>?zUJY$l8B3>UYCI+^ z7)3%3)siw8;W zTmzr7$cM_|ubnh^qLk1MV!~uw7<5b~#MN&%V@wL5V4xkpi$&;I1P5u?@-We{K~DRE zb201KqjUyRiClHxDbN6EN@UNHMU~(LoG3!TZK)4j_efhw{E#+mD{3Tj9qF}Fd4(v>ywwLCBb_8WCO_6_bf1hexeG=U-wdfZwf2>- zYDIH$F8&T}KDe0*m%J1P$nsg+x{&2reLwIA${4In@*||622;8pyQJkR3Twfd=G$dx z7>r>omWicWaU+1Ida8MY=^D^{Z5M;)^TQn+cho-nS!%m8F6H3JV1-*V`qM-6-c>+I zmmSN?VyJNR<2=d`$wJ2)EY;|UCI8mzly@_Eb91Frq=V$)s9xQ%*3&1{7pd&q43uHY z`^^g83dp#AEocsSSCpdqHN)a)NTHNwekewnxRX-p6zl-mkg3oI)FvZW>5nJ9VxD;7 z?ll-I7r*EKeLWhM?RbrmNpb>?SmNy-|{Dxq<&oD$f@v}Q=~ zTXNUbI)IT%w}eb6yi3z>6%nNgqxOT+oW*MSx$wXb+k$1xR{ZHhpO}j?w&**=IEv3j z4;doVI?IqrZr|S_vh#fvn!Sd6r;z>y84H6;(YMM^R9~SUmVmmJh=)ut$uxT#9cG!a zXOE_m&f+KKPg=ce7&2##ez+}Yzm4N8-FohGVt5Iv9k=blA(D_PF{5L4mei3+It09R zV|NnTF?>6dS*B_nRXI=dr5o7vrBieJGkNqT_L_Tc<>zg^l}VN!Jd+^8rR&ZI>9^$X zvIuGLGPDl*R8cMH}i5>STf|C}5L^@$+Ku^?0=t%(ahkHtTP@ z>adP;sT>ohB2Clr`n2z?l~ah{-T3KtNsP2_2(pS4XaurrQ=FR!!^E`bo#x!NNCZ;? z)LV8GRs5~(1foj0%yQ%}g0*p$YR^7_Dc>3a(#XO?#2dwjOts1RMe*><^3qa9+u=J` zu7~JVEWA)**o%F-?94*~t}GXleX~T(;E(|q2}u3t%VQGb@{-6(RmAU5gt2HlH&055 znuQs6VbZN&Dwzmw>331@s!i?;LmO4Kf~XLesB*?LGjugt%ERj~PaeZsBtHb<#)%|g z;j?$CjjN@4Ot0KX@kG3)%UgkPsiyB)keoo;CMj4%mz5O$7R`VMrShMKXVg63SY%Dk z)0RAQ1T$?*TWLqg4NxakUdV*8q~13QxdPxy#b_=?DbRxS$lv*~Pjto*e7(b!go$%IOJTVM<}x@&OCpf{884NU99E;y#c}Hz3gXIkrVYPRoa%OY%&Z zf~5=bE>o_hMeO6Z^`gF6NS?H^6|w1J!#V?&I=yj!QJRv*$O3`p8M&!UM1G^v5$u~; zuNps}I`O{#N!iH#ecxOSdKPcyALZkMyy^~Y4-2f=JuP)r#Lq@&u*{;#=z^l~rD}Ek z!HRK`!sv{;q^bbI>59DDoZ}>^WFOx2<@ z{J;kEm-2v3tU4wKmqb1&O7%fjuKS(YW1ytR0^h)YU*Z;jo1;OHn4-iY!#UuXc7dfW ztm9lC(t)}YlKM^x>D&TV{6#?&`DsEtMNzv`qSHd`1`>-eiF2pEOOm2STzAW<4dzE} z4-Oy1LA;tDn}p0Gj1xDCQl+dvwITItO@q#9zTrr-QW=A9k2KOT@1eInG$#VX*2eo| zm(4FCyR24shG2EEp70s>;t8;~QQjiJyX@Z28u{hXj$IqNq*U)pwfA}Vv)m0u&gU0s zUz&Nibl;Ow4>=+<^-eiC!h7=WL^#(jW>PE7>{_V$OQKV7q{Fek_cQy6E)hb2c!L)w zl0f%a$O1R2Y6n0>{w`4isNqPOEZM=LQu@wm986)d0@)ws8RLjYz^2zR8li!#e(d0U43RcmvuAyej1YF<{5 ziHo@~t9xwuxVa)2Rqidf>9-5$M3En;#rsdcDGH<8AS*SHE{zB)1B~6sktB)Ff8uvX3DP*oF^5~EXt{W?>}Xm%vXlO0;oH z{F57%N#?~ZXZMx#0g5(Zi!+%n3p=<75hVE5*Yy3kiwS%qy8JE`h{7_1{U%v$oI2rn zO7uN>yhX=4bPn{sKvm74vdD98;sE4AMVLtZ(G&hC{VL%&H@>Z7{rAUy@)wdh4d`Gm=?wQ^bd{`1mltkwmiO4 z?AAxVI)A?mHRBS``v|nWNUS{Oxpivwg`9x8)x%%BM6Wkvf&@JcF!?VZ1DM-70)IUQ z5D2SA_GLzce9ZPo$5_ME&!ASGcvsbN=jq4rG0Cbm+hrl{%;bns=!u@>iEQ>=4^B13 zP=X>Y0`4}iVS8QxiX>2XzRg&o7WLW;*APbc)(8v?HQXHZ;6Xz{o)>6i#b{t;V`$9i zYGn&j1q_T|$ko;WXkqLKFf=wbw-z8jZS5cjm>UU@f8bDHRMUGS5yPK zTL5{C$b|$E_+5EH09MA11^`zpOKS&SR{`?hxV)gxznYoI0l!5YEds7dA#4ds8MB9v&Vh zW>zLvRtAs+gM*v3qk$`fwFAX3h(8$O#tuMx5P#-2)_`A_28K3HjsoQ5p!uqUd!UR(4_sD@bz1l-@NjQ+W?(@4JsopK>kZ# zULzZzxe@R0kDROqKqF2d4}%Gpp&lVQyMd7b1G_OdD}x~ikc$Cmz|O|b!)d_DV#xD12qk-S zkS7>e{#~nIP(~mqZf-ViBOX?61_L0-NZ3u-SQ)svxi}bjIE|RO*@0}vtZatAp?<9c zuZXgY068lo^S@e@Ee#w^Z0xNB$mPwgom~HQL(SaESk=+s7ilb<%-mdT%pBaDTx{GN ztgQbMQa84D02%o&OcrLwzwQ_Tc_l%J1|VZIw=ys_X0o+5{oUo)vhac?10vSomv4ZO zf476?0xD7&8#vn7tJ&CC3XuQO74Qr4w@U%||8f>yc^lyGj=zPCjehytUmhoFV9NCS zlAr0n6aL?jRLyK$tpC5^{7dwoC?fWbE;jZSO7=>IpNxTy|2@usCHzk$6;P~maI|-m z`9DnR{~^c!$6TdBeQoUB{x-gmT-dMyGWCNge2D#Snbp}xXwmzDFmv%8T2H6N5GczwUGx?w81@JTd z3aI~>9{;b9qoBb1cLMl-g(O~?UzVrpWNT|_ZfyVW#Qeih{$J$&*8eY~{6BU7yV#%J zVm7vJAg48RRC2NYZ-@Uc1pgq&n*)ul9c=zP)&DN?hnBzXJ0P9^w1M_B(Dumm&;9W) zv-ssX{}+G$GPnPWBY>d)Gsypl-~Z6{AG-cW4E&FT|6^VMq3eId!2d}2Ki2jC8(j$h z%CL>CK?gk-Q2spjR%{;ha$umjn3%GRnAktw2LuD7j`fNaknR>H>eW+~m<$VmF61^U zQN$6KAgV`@C_(!aq)sf)`0W1{Stcwze_hM=3|M`zzFAfpPzr$a_T}c`rD>7={3?gQ zV93vX(%2n~EYYt&w1J+iw?g!zSXs}>;^@#R>Q2R^J z1RVYMg3cLz@MxYe6<0|eDzGMkGL`jp`{)xL$lBVC?8c}~%izITNQ((NG}5XAdw#cU z4@LCMwuo0{ZtWbmb`M|$UrM);ZEfKqaHu_2_EuJo+n+s(7S~Xts_bh*2ipBWwGbFX zIVo|l*I&Om?Zxq+7I<4}O$RVAMv7m5;I4&2&Y(tEM;QeP*li?SWJ&@BtA`9w6TYK_ zhNGB`)vqKL?5}hQ;9~A*2Kbd*eegrU1p@Kn7A#5dog3pohShkgK{4_eT3x-ge(!%Ow-ic%hx}F()R@r{5OK|3w|RPH1?C_pvZ4^i~GSk2C7x_T+98Ic9}! z^Ryxz8e=vjG4t~J2KwPCUNj^vZ@I%8eddK-R4Ao8$gXY%E5DVbxgWlxon2Au6@1?R zSP+O7G}Cn`6<>I_pP#vKjf+u7rDa0t_hYTE#>QD$RWaUc%VXJ9$1ccU<_~LIX#H3+ zGyBy0V@}aam5##+`N2$~ebwWx2h_Yy@W%$4|)|r33wW~oMQW5 z^9Bu-n|lE17Z#UM$23ADRA;7t>gm2?9GjUH!N-d+GbpE(-G2Jf>u72|O?V=&x;gQn z1%|d%sj8zUZ3XtLMz!7Jq|4li22vY%8HBU6GVULfk`~6zHht5%!t(`wy2JB%`#TNA zu$rPf>v{DgUJ-apykwpW)RQnk7+9MO!gD_2``+fF?vd@eb4=XX+Bw~+1)#PG|EG#~ zZQ9v(!77bdx6=2G=J~KYBjtEDOoO96_y$s6>XUj#0 zlpr~wiSQ5BB{~;fH~oIaz5)XiE`OY*M}m0=E3~SW8aYwl{M!^A*KzErkK0%bUuCma zV&b+z<6?`?ntc4#HWbV)qw;h3B{^H%R-e_1lfJk`x*ld)He>tGf9VpYoWs%4ZZ{Ol z=lyd15wns&OV&_(f0~|l zlA4*o<>y`jm8@^CyBD!*EmjTr+*Ft$D>&aC%R2El08DI&=K+u06h|hf2TLt1^^pvG zz7zv7f6XTl%F#|!ConjyhP^TRK<`Rut;I?GM0*@6F$0g#xqa6Z^#H*|9!u;2>+4m) z-PPBFC7O`Z!zj95X8_=|>YwY=MAY+XG+BVs5H{ zEVopaRum$9m;Hs$Ik_{iyzIRC0A{Rx$O0FrN6E2oTCIPeHXS6tHie%g5Ny@G?zRk4 z2&|>>O>4#_e>NvbeiniD7vVhS9e5UcUF&n1KhD^5Zbfvkx3_0wVHqIX;_iBsvm9AIPX`Pa&JPsMFkl=!V`S*TmB_NIS~J`c}+5sxGhASj-` z-&i9I7BMk-JFo2!85SMwa)3^x9$8j&^p@< zn+E=b?r=ZBaBJ-O$$M4y8AtN&BDf1uOA=q1>D(-?teC>jG9mg2ITDP7f1H#u2XQiWD&COd^{PHyVCyu6L*`9We&s;GvdcDJhr2nn!|5Gs zP*4!{^&|v*l5w^B^`~!-q^M_mug?M&^EO70H^)ilX$3_^w5=A2wM>ly>LiM{6$wp$FtDyR4Lh$sSVbpO`5r=i(nmVn3I zPISk()rVWt@9TnP8qIyLoBk4|Yo3>*OWh%;{RIUD+=f7)jGP>WkkDG$*RKcl9=9i} zohUgda07*ue>j73Bx4NCRZ9qdZF)>AwSJwmswKjwf&Z{7LK`%f_NJ7p+H4E`<@lvC zJ|V$zsd8p!=4>H9n)wT*AO2RzR55e<_MOIMBsM8KNh!~H`)uilN{@{oTx~yLzzVy< zM_pZ#09aJcn%dg%C?X!#!iEM;0`9O8Ib6{|vQsC#wQ-8;)?Ope%D})=Y~YJ2%PQ${ zf&&FeGi~Lb7*#+Ec{Zerw#)2<6iM4-aLOvQfFj|ASM#)%L)*95p#w~{dCoH*#3W{` z6R(j}HrQ@v!6$+2@qUMKf&Q=aSvyp>-hS~x=UQG?{I#}UzFqeFxZ>Zju0!;1-QR&GdjW|$z11^sB{oQ3zp z;g8SZ;e1xDAm@9!uJoa>-DIwwjJ<;tAwuEXpJ4kW>z~dfPYkqPsDAaEUt6n_v3N$v z%_??@A`y5Po6MKW_ru76oq#KgwPg(4SJXufolX|k5y8!LVZo=JoO+sfIcYNaZpB7L5L*#ig}O)Re6n}Gr@L2l`h?o? z(r<`DTv}Aql5~K1J;Tv3F|{PQbFPKc(Gg4fv};~Lv)WG#v`jF;r(eP-c-`h}`q@XQ zgt)I|fy1EHqxW*@okx+T(b7ziZjN>w2H@nq=r%Z$Ij>%@ECLP=Ar}hztb64gB&=A# z(!wKSufWzhZRYa%^+b_UP0)U*MBA+OtfYEl<_#UOyDYh$8W`MB{1a@LWR-?a^;h`K zmT;etFs+7V@ai6&meln)jDT-gVAea-w$NzwA{Ba^4kub_jx&A97Ln14ae`Gp>tL$T zS1OmWR>T2q+jaGgn3FBpA#XkK(`=}CA?8S`G*mNt8&6u(>gwvI8@#Ue-(}qo$9n=f zk(g@EUrw(1?`NEK2aozwM7;2X3P^(%&BYgv6Qc2ZYRrMM-nUPLYvA7yhz<+H)QE+u zi_C8vT2}%x6-`OgN0V$Ce{5}SZW6tF_ip!mt3Lo485x$2j*b*^73}8*hN!2C1$3<0 z3o@Q_783_}v_JBTy|9RT5@uT zZe}AqSbsO9&pxxi-S zp9m+{NwuT(zDvW@8Ljn(%xTpG!8wC7xl94Hh4;dbuKj$OvlT%zgTw$(FoI}-!@Z3n zS@1Y2gYUL&CNdC^UOKec`+0wQc67;fd6_PF!1K!Ol>{_H{QeLCPOufs>U1!p^z`fp z3CmsQB_LKzXv&ZLr8+D@@GV7{dX49{|@p3mcU$?+<2HHY>Nl=$nKYZY-FE5Y$ z`juAe<41FA>msRW5^)KM%yWrggP7RZ4G40+B|rg}bSNU?9uQvPeX4XxU-uUnFl?=A z)ZXw_1QM4~;F__mwsU#vX!AIq5FuuYuVL7Hw?oA}6k`C8X*T!PfgsmEvzQjT2&~cI ztfetyEl2ZIi#j_S*uGWLd{wyE+5YgjPEXQ=x_zO>m8(bnYH*lOde{Yjd^!9hg&;h|-aLsl3MCp{y% z5|1?((@2*LELR^K9Nd#YRh8Tc0w|bcO!O9-fNga!yWKgl^`UlIqn^tBly+iJ zYCD6u-&MCJHl~V5y#H-Lw0#6;bk2J{MwFDU_Yn!i_pqs0=e!$#Ay6hJh64!M7AavrXPnwV>Au6!; zk(S}*tf4n;>uf!yOI*_19-jwv?j6q(aAS4GKy9x}=rMy7!>_xeFt6K-oA=>1=1Mxh zxxE-18X|xD7AARELR=imx%IiOGaE$O@Q$ozqxH%yr_E}c|3un8ZugYdIONdn$%@D0 zLN!pR?H1AxECiLb0-DC2vgh6`<1_hyvOcXT>D-Gsxo>*n_tW$)$gvORD9OOf#Q4Gu zk{r6EoqfMe!O9Tgiu;+6VHOWMX^Bf_=1gUZtNR*AHilkA?cmvipx=kQWR{T8HsI2} zAEXpAb(cw+L2GtbPA}+icQN#R{!XM>#Jk2$3+P{%%K-KQxCGzp${Qend)K6=4 z2{J9wgM-gPzb6zOlu3CTx<1Mj78def3{Zg1oI#*OCN3@xlyOk7u%H)De^x>0W@bi$ z9ImON57%c79p8IA>mVc`D5H7+T1d;^W8IvG*wNL7@S4mJjYxv0yk-MxO zCCmNv(Nl2M{ji)iN2|h;Y;4P6f?OqFk6g@>(l)%I#JYTaa=?w<$%FfLeIg9sOj284 z`I-K0ZtjU{TJh!he$Yw>r@IBTjM+ED5hxM!zGTOUoU-d?=-v`+@@UBBEs!~bc7 z@^%Ge?;NU_Ti>09>gUQG7YdR$jZslFfa(n1&C1l&d<*~Jl)xSEd_n^^NyK=g9DTs zrBg^nRb6E^!okpAIH(NBes(e{#u@#>>z%i$YtJ6*Kr%To z@H$GJxN?h$sY4>TI>Z7dO;%R~vN0G+6!UJK(Umn?J0KPd~}AIrT0m zej9%fMb^k3SsJnu)oswvt{~4gvvqo1-D$Y7B_C*yBmStT zH%?dCrgA+c$Hc&jw3VD>Y$XWn4pWiPI;?qm^1PgpjNq`CtAjYqee|dfY#NDxxZpMa zNYm-^KBgt^omm;vXJn>X27dL;;2VY-%hQ z+H#IA{g_NXmy4&%@ypdP?4!l@%!mR!m?RvwW2sv-Lc*YK6T_6;`vX~;gxs+OV$(F^ zwwt+6FxPafT5ZQPB+()7@+HxcU{YC)Wgkl3lOR3MZ+_UgWVG}wfvoiE*BywD+ZQ;S%QOn8SX-_7 z({8foXcH4B2F+U-!B?E9gGswW01OYKD=YJt7a)%tctWSkvAPvXk>N2 zqGn}fwdKvcd-jeZ6&mY{By>AjG#!*@Pi1Z4TGaf~1k6*;)oBAbw?@`@OU!VwvssJN z9yWS+Vk+^A$l9~IK|>=EaK|(|>|tPHs$QLSqrO^!HXxyfAIIZ&&o5wS^{uDhJSKWR zV+vWygVG3kofftEnHhfA6}AlZ&|$7zwn938o&MrQu=ReC(GGAzCK-K(ev>Ya3FDxR zu|6n%EtWODpby%w2M=T$FNg2InYw*R!6kIA#;+iQAuqR0&_N`DGONTdwNxlfhl$BS z=6EaL*a*(*>$k4!H!N*i&lMh8Q0<4|;_n8O3vXs0>Ai2XVj6E2@8)zc ze}0S$!LAE+kaD>)%Km86U_i|}9WNb9I@CFpWw}zFXtR1tX(bNI(osKISS;3>qVnKd zTemp#_TFoXOYjOEG0fwh@0(LgXm*gRSF8k!zRQRo0@YgvXFhi?wml#_A7>0W&Fl1M z@HkL2GLAhxpZdIB7H7F1&;qzk$1+lHS6oQV&CN-zPeG+r%Y~{9jrZ?oOMg3=C&@DL z?2ls|oL2*+uxwYlrZtY}mE@eRT;GZ1%af9)RHWsg$oJY$adFu+6SDYWdSJ#nPo7Sy z`mBhS;RWDozq6~!d-Cv_xKn(d9Pu~({kj)E%Qf^%&)^4XS_@89VLGt1nxI6x|I?wE zz;vdut8LFxuDaHJOWaNBz{X*8OkkJr_o2NBvBEmRqR4thOfscd^` z&yTmNy1Lf8ySv^C%KDl(>6})ZpoG*1T~k*f^fJ$YTKRkL2b))R7-sy@Ze3J8htWMV zTuyFojuG%+r*jssrRpdNyYkA6H9p++)2}`y#e9}rdeMijqA3^n4qGO zWOC6&w!Kr3?ZAx+6+l!f*mW_RZpVEjPr|ibRy@y+q&+rq1>XLoFoR zB+;$A>jX!38sjHhYRGT$^O11exbHeMwVZUixb=7h=+L6ZcN+k=4ZYCyxTSvh3u{ z@=$QOheq2KB+M<7!N{4ncni6i#qHK*JtiTh+nk}jEDe1*kL?}xm%(#!?jt19<&a*) zS5zq}X%}vyY}ZU<&7;-!^x|x9cl0WbD^JEiZd?;Hp1Rm%<`K!9J96d2@^$oiegZy+ ztyTL?zem3aX72WOzaQ<>_kI>+44KUvbM`8An?E}1lh4}2p(OL}U>y~h_+mrBX=D5!Tcz73Io!#H)zbc!m^$2O}M(PCfEIV7pdu7i%^eWtIMQlw80N)TWZv zi&}UsoJSP(^QFziJ5Q^TRG!!#hZG2X%`^(B=*zj9ddoF0Uz)8D=DIR2s_;_|cFx-U zOb*aK#Aa`+mq(sy3b(%=^?7q=KKb3+f~cV<{hOdgc|6U&Hr$u!?QNrqZx07bP@bTg zuF&iKI3}os?$KpZI|~gl<;U0((nu5}QX-z~Z+mKd<<872YQ)5NtbB&IF38TIi|XSz z+CNXz&xRQQAkjxyVXJ#aIwoEA9~9NMD-Lo%ousWByT^rRICiFqF2+*Owcx3bHTd?n zr4b?srG9}Hy25SBmF`!PC()!!@xjYrDJ5b#V%vJrZ$_Lez}NN=7Y_Hoo9Py1w}M#D~gwhVlVx&oGVjx`m3WZ?cs;1Q(}GP7KJV+K2k)?Zeeh5^^_yhbBq@Hfp2F zrq7y7v)-DJtti6qDhJ}_etB(hcsReR>MViWDQ#ys`D3)u%bo1Ho}aKVNvF6Al%F*F zpfF6D8J4gAUNwz4*Z(oB4y*ie}6ZIX=GW@cX8QybY5^4fXuls&W^EIxMkb9_PY{XmQ zP<8!Wz7weuCufy_m_O$ohXTm>p?;*A)S^WJz8IqM7(ogC4lm>oC8+((+%fKE|h8v)vr!6!5vN!4}-b^QU57p6GaCtIO#w zSI51Aj)TLc59GDITeutnRFQ$9O0db>T({+BPc@D07|dVR{$ux{GfBm#D7+=zAoxOm-}W#O(WA7ubhLc-qn@=U^8mc+}s-GB|jZh z??Y@NaK$l$D}A(sab_2r7!hTI7=T$0?5oQFbGFdfEZ6^LLGp1M6ZCojsIYYAs(j$| z7-1)dP&@rIYU3Epxi#}#?BQbB0>5mvF?&-D^Af1q7R_b;(n3B^xi&*-Qs8h{R?6+( zmNZM~jJ}3$$VZWJy5tc$zp6EO!SMr(nr6gku8zgXv}o$!dgHQw3l-`N*59?=s;>U= zi;ZPbLxmqjV*jGcJ|3o2GK<$Ha~$SY)eof(==8LYi!N1RX)SN%KSEW%bN=SKf^|SZ zFiA>iwSQf2*Tkyk+YX=#Xj(9zpx;9*HvLoVk4DBcN zS=MT{-^q8}JbOnrMuQXxv4I>IOmGV&sEhV}1${v(Ck5Sd?_Fg`vi4>#*j5mhDR%5^_A&^xxo?#Y&Q2x1i-V{UG#_((rXrg=Wv(x1Y|4ph3k-P?={h z2r`AoS^pI7wmCUZC}6x|in5^CwtsZz zN?NI?`HdQ|q!yu@1{(g{+8uY#P!oshAe}j(D_u@Ve`E6&9?Jg?61*%YsF1@?7){NL z+TGKVJplH~Xl&$j6EMGeab&us45ACbcS~frctDIqDDe65qy>Mtrs?*CugP7_2IhuN z(xRl|%bu&1z#}T@ET1!}+9RrZkS-})UIIA-j~}6l{C4@yA-C-v9^@m=`Sw=y#cjvy z3a|T>+41gZx{nj6PNWAZ(%jbj262z%hlNkkQ%` zeWJ&nuVjEqPIPn9uB;GGSQNRN=EDH|_@2YuI{pS=$!mH3qmf?sf6?@nQEhfj*Eq$C z2XAqTyGwB>PK#^N;;zBni?_H_!8N!9DQ<;O2wvRX;k$Z2@3&T1S^04#N9N4zJ$vS` z@GZt$!8O;0Qds}{7eM*;!?X%Ga~<>=|0Q2aG!)~+m_*YXK4k@X2(6WQ72^QHDAu38 z+Z{NR5`Li}0a(l|!;Fk?Qg)b0fp}X|N}tnM*iG}I&itHX&OvnG(0h3>9E0%N&z}~5 z>Z}@?8wm)hVm@X4p5s3`%olrWQGbk5Lj?l!u(6r6W++*p<8LQ2j#G_Qd@nw|TZoSJ z;A!B?v@rqKn=fT_tngxAlJ11J{FKfyg_DPEy_VLt9_KG$Kw5b_Llc+p$EvrH1qp&k7m;3uV`0nkq*tyn?)( zy!>oeOq{$CKvltJV`hRgET zO91+_9CbYhHq3#~kM@;R)uilI!=e8|;()a&g-ebGrw?(>W<5?x5nm zR_c0mB4&co*pTw(!kO#olho>Bwm0PkQjo%&1ZigUgiPI>7{Udl`}i9sUrRS&vA2byGZrn z*F6HBbhEnL4a9-iughd7F{r(fQqaX+VZs-YRL8r3(tIe(~V$EsI^)1uJASY4A7@m3FwrB*m2In&Z}T(_CgO z9tr>~OO3T+?mONA6{4Yif;scv9tD}vTx!Jyy+avLxv{IRFKA*vw(bq%y3g7NNq~i% zJ8u~!AJ*`u49?RHS(*0@qs_zfiUEyPDaPr=rSv%cd;FWl@U7&GYNO^2`=sZ~*?^#c zE6@F}nIz|P(~Sp`K19{kxuI}ur!T_X%|X@e3L!1wx|+>9Pe8`NY3DZ70K^wPEzFH+CKD-2} z+s4$p5Mae$`*A$-|29x7)OtYj0Wr5nPXr-<2`#Dy*I~Stg$1@?xiX@DQgTI(x?+(f zL)$qrO?by5=OxbrQ>Pk%1=VH;256CqR!G`@bGBtV1HN8x|s$s<+;j8~8 z(p3Uo&d-1#ThMu{x$BYr`DRcux<(%^4ueL&4RFcfY3$Z0)I_AIp$KljkcD;rSm0Ux zv zeJWj~_ZOG+zK>}I5ss<$L!l%7wL;kOT2 z;)H;J87Nj|=jP?{o!OBTw{%ZZaB_GCM*GhFOVHebx$4COm!Z|$|DrrAJgq1P+gnpj zUN8JSH3#2o0A~+cvi2xE_gmT{Ev`Ms!|PC-l6-hs_1>=jD?J0`lhY>#+uVBzkTSQQ zt>lyNvtu6kOeyk$bA3)&dl$w^V-vnXXfDCeLLD3qB7F|LceqDR68HR2++2w=FKzql zUSjoiqRl{H(SGeL1!qaxvRF{s-Nk zQ83zV@54q1mIGTfcXOEw&OZutCsqZ8v(OO{BD*D9xKxEsAEFY~>qF@%L2pvjw4&RX zP=1u}h~()-h_*FEI3{>ciACP9h*S3jq_atEyDBs1i}osDShQA- z){j~9)R=N(tr!eJl98julFl=7K!c>#s_T2MGOmNNDWKy4z64&eB^Ef<`L4pn@lXYZ zjDA;u=^BlRkyx}w@;7aon}_c4M4H#FaoHM4hBj*DTH%rHl4WLQKciM;$G0^y1OD26 z40a9wp&wPRw@R^BOns&({Z_n=uG@4xr~7vz4Fcz+^0!uh*1|0EmdqYkMkEUrJp?}Q zS;=+Q@^2PZw>VPLOwP+FXH!Bzg%NOSJ`3-xtDFVr$=s2UDMy$p#F;afB~U9KA7Eb{ zRQEa6C+B|k3zQiVO}6@kUAnW#O5>={77#?}c(~p9zCtTD90J00=T%gSm9!ATd!(iz zY0nmS6*~ID%!tG3=@lNu+~Oc7bn2@?wI7f}`UltYllOuJ8 zTHTg8P+eO52}4&(NRm)jVSWrv`2{g&TqpLGAtK?_c6(Nj?`g)yNd~VP>k}!Y1FQFT z$U?E^eWruqe`y$35(eIZjLq#5hNwf_)?&Jr>w(=0{jS`-tX8ZAdBg1I_Rxzzy|)97 z{s6jU6y{F+Gc$Nr-K<+{wa&Q*THJF;-e_QyawDk(qxBZTrYkGSZzRkJfL7)K-T~`nP z(eG^qjW-Rg_Slkc;+Y@w z6dE347s?rD4>u$^nBzYqXCTDE-q%e_Sh9}1Oq6e-J&C7~hMtNv9g4ZUHNWoQH=J+0 zenBdd)>S$?_#~rndMmAcx(=UG>9P|7l9^)ndxq`TJsELFrIP7T^YW5caqMk)MU4Yg zR6~=U5osjWOOe>_q~`Q5`_yb-oR$9YOu>Di$Xf9e$3F4p=v?<3ByepxbBa~di7dPB zcPjA|5s;2}4#We;yc3+JBl(r~uUZsfBJbz|7ow+M1Jx-Yc^^}1WfnKy6tcPMXnqPW zGyQE7B3*mckL}st6q#ro;33tOk4V(Z{Hp9GO~=A+2Cl7t`-HYk1i!+mcf}qjcceKB#PUOTR5tGj`%ld#@m}wz=9lqtUC}qXI^3cZ0 zJgof8gUeNVzH2f0W!0%69-{bb_0Afbnqc(J^Ow~`&G!8(7y(zN!?9HY1yK|3a&vvFMTK6UjD=DR9B(nWKkg5Pl=7>N zRU(uVf75mdfV-spM?B)=Vh)hVo-gwW>`zhAB0hn9o}P~%P}IUC-Pp`I7(mGa65mTE3Ff zr&!Yc2yGUA+D*96={WyYOh6uxTW6fIzhr(@R(XFT7=MraR^V9TR}Uc$(cheB4SlcxkG9Pfz+688V}nge{Vr*83BW`4;cSyU8ZIoe6o zKe(B-3Uxog7>oDx*bVl19k4>*#x1m>8FV<>JlvO@*bYO@AXjc*As%&|H+c7j`Y&5NM z-~=HsA|yI3KdYo&06zG?k)PGiq`0|HYxf2!G|nA}X!NHfEV7J_3GFYe<=7CeLMOYsxd7;&c6o({QhD8d$kRv+82S&&dIfGJUwB zaai<3sN`p_l(5?;7dG)vBg2aIIZFs?bw!v_k&A%I zIQ@)bJ|@dBIZwCnVP)2c&9}Y5C|o;S_kI)YvO0mU=eu%4ZuI&Oy}8|;Z5p5PjdZsCN$@Z?JlSq7T-Y6qqXr}#4B{TnEy9F z-_+dE;52zDkunQk)|L*XJ-ROeGva?qE_;BY!op#@ zy!>l{pI*P+8~8IeDU!~A(U_PW_Y^Y|?|pT4IMp;>LI$io~)aQYWHVnYrybw#wmKUvYZif^Gt{s_6$xAB=uNkBJB0(_1af2V@`39`%sy zcH)amKk3=|#WD+6?5S-a7F_N+Nm2L%N-QNbZCmkm_>O}B0O{$YmM9nK*#E>QxJ6ti zzUl8Awp%u7BcAv@1!Q4K>sf$&wvlK6(K}tI5^vXWVZ2OTTTB)91uw885z$2 z74v5Ay4C`QIG~;l9TQv%Upe01Ezc{f{GKxUTeczcMHH2DTYj0&an$`ZuOOkcyY-S( zg3(k_HnOWZ2=yX0r@PVCFDuIi{1PP+Dd06*D0Mjzs1$jnSrmDw)DT#uFnMNqTsFg^YSv` zZayZ6-rj0guU|H58^WYMRA%M}-Hre?&p_m{ZYJa+@@flvyuYgTIy6`gxTd;tHXRvd zp^J`5r01gpuI>Fg@7R>cSEBeXHcVr4*9Xu`4UaYCDyB=Kc8|!y%R(Ot=q`kMYhJ$v zOZ0m_q}hI%I<-;jt=B00a~eP=zVknQEVpEBk>Vbf3cT#%$l|?qZZqWY}|{ z$bMUfMNUoUjYZ_uMq{&1N?wYTf%1BbuqNP)Ue@|z^-KYfyXct zE-lZQrB#4j+lso;d;0G&M~N1}KHhv5BYxKHZB9`{O$1BI5pTXRMP73#hp^%|sdRgi z9oV2{feLh%c>uE%n?7Sv8?OB-|K3l_$mcqbwZE{KpHfWc9oT3z%04bX=QyCyNDZAX z>Y{(wrN-q{IT1EzdeW4mhQ7;!fqk@+s;{l!K60sjb6>Q{=I2ax^hL3Vme$t6u7`?3 z?l|=Q6TqX~{{F&WSX>m=^hYu^6a_+r%2%#%GHnH3OQ|82HL;Q_S-M(H4xlYaSbt;5 zynd=nNU)F&G*lxq6~M=0PCW@!MRHOxuu{EvEo+lX?cu8BRsBG%d9-tK{9a^gQpH$? z@caoVVsqg8#DW3HU<5#ZL_h@SDNqZChK%eAZBJJ5(=+tBI`#_%J~!+7n)kGgW(h?8 zE`eZSJ~1r{6%`v@unf^HQ$YziIm>2Y<1vwpc4~YYMw4OFCbty^UAa*-PwJ6)G(DY< z_rgWlyUEGYN%2GnUW-ifFK!+Yuc&@lYE*-#Q`aSp!p595hi^;2nA){m&K26-i>(bSQ=<@{v<9t-*U<96POLLQrEe*AWsYe6Gcr{? z_@~a1^XHt?Mnb7Q;NKJY1pSrN;-Q=ILgk+;iTdOfQnJ$rh8qp_+deVr@3Qm_$ew-L z?wigkurk*tuY60k*KlMn!}9SXZA?tUmO5v9&yR#Q#dk5~uLM)0U!aqHk3k8zWHY_O zU06|`tebCjm$Vl+SnXbWlSoxvz9ox%nJ@m>qL`iH zD){7lz7g;8IgKc)l%JyM$lT?b0Mm`P=8uXWiM95Z{0P{hJQt{M-@d$M_ML?V7LCKg z(6TW)qy;QC)+tc8#BKCky3dU9!SQ*=T0nK(qWIPOA>+{G9g>U~Dpd)d2<2$jT%_0q zAdgs!z+Mitx&Y90d;^65Xp`c!CciG7#}Nx&JyxxFLn z>&(E*%UWM}KG}42OBO7%VqHDRRI2}Pay->?{`?o_hB-aQtHb7#H(&1LYgam$v?=isJ~h6S0SUYj~zWK`1<#Yq!26tQbX9> z?>t+x%e%wEx@r8vfnX{B;I$6Sn`QXd3-)0~TYZ4z6d9>uZ(InD@Zo$crhEI{p&lPMS|BVjFrljs!ezlfMKDh}I1@mnMshxrhwQ#sI?H^6utwS8ky*q*8#DLsvdwez%^mM_tqgTj{7mLE~9GYQ|8Fs@CNJPq?t^i z$IcHt*|9;)pN3Ptr9|SNr6Z)l)M+4dz4N~P9u$>QjSPAFIH}*gCwCP@|0cUWBa2WQ za|HTLe5IJ1p7qNZrncpu^c)7K{`A+XJl}mvuvA)Zc_4`m3V@6A^X0X%(*3UjMQLr; zszu;~0*&M*ZAcD2_JOgKmJ!<`E~WUp;3;fQc59zc++7d*tZaG@62!VmeRX`e*$Hh` zU;A{oR5qnCujEAN6r&T=m>QbuA<{l0F|x_!GW*`7$hDZ{!Bi%A*=g2Y?ug4S^SY(K z5Q;X93D;xGgDHs(><(qUk5zu6m%bhjmX^*>k1*KK(kRDn@)LLX;4&$kFW|fXAHCar zIay3~#d_`rGBFq((^lXHMoMF&?={%lG-b4L3u9O#2VsLjU&3`wyAkH32Ov#0?g1T0uqU@$Fy!5dQ%UadYC_tV2-wfS zq!8j{H)`HUVkthosb|sxw1L84juiILfi_o&6M}Th>Dx}M<~7vwpQjmQm${quJfvS% zE`5D-@t#QZevUEGV(z4LA})QV7#$v7E@o`N^DP7^wQ=O1I4 zvX$XASFtkwqcQsnw-cYKp9_9mm8sMx%{70_`rPky*nWpU~nPR zkiEv#MhnSiBa$UO-!(%uY{Zb0MKqpHc9zu)RO7NaQ8VJ^3(^`_37p`s zdW}0bBqAGGvj-9Ck8aBlBTELE$O1DOw**V%TcG)lZE7%Q-aB_hHX3@>T0aU@b-8g! zjaaU80a2Nx-tXO`gu%@Ur1g2vpL7{yVk+1WG2%Lj0&U=62htZxcM+zX<`aF2e< zs!q$+W|f5q%E>^TZcOUo@7IiF ziAeMCl>dJ%z$C+xT1{dqs<_D7+)w|wic4v-Gm?!3+_kvl)~P$E z&u#Sw1RYhfdRVeK+BTH*%h?Nvy4i7rolF^4Z|%LaCcrhB=L+hY7!30^8U)PA=iv`b z|89@`3YIH&yb>^z9#3u3OV?$%WlTl%SM&X6?`8M#32Psv*QmaQ>s7(9@42EI@q^jk z%h_P5*ULs@z91dL8`Y8=m=UzI9kZyz9jqB|^-Z8q(F@h1og%J-aGVsMC*ynfSQV58 z(cRa1t$F#*C?^a?Q60?j?~v=jeR#gs35X8IqCQBFnE2s8pUtYzz!!RQzHhKlXfF7p zr%w!iAXT>+hG@dUn?_IfErPxWx9JGj6k5OX1OGDWIL(h68eW}rAHp=X=G)%MN6EZJ z3Jjt)nW99!z$Vb|JH>nmXi0?7KuGiu+V}M`JUO=Ta2+spa-O*+etiV%4HO}{(*7v} z$teBBRoVG--t}k2l@u|5q?CkYV~jIDp;=4L^bM-K7sp3+i1J8POf*t!Nz!|J1-`F} z^z~af=}AThHZ}9BA^P{UwJ*nWH8TfP6es0uY2f> zB!fsKOpnJon1``aDNeQ#WD1VADBd0K|3FT5zTd7FMlnJ(a$v*LgH9_7cQr;DuVH=^ z59A}Ii9Gcg5r|d1dVyGcx)zqFo*lzM>wv@SdYg7xwh_P9F`|5xPU+_?k{k^T@FL5S zFF96j9it+m$As<362uemWP%(>Ll=o_uBXI3XFxgF1A z3Gfj|rrjn$u{QsT2Df2TmmT&c9}%$F!Pd!Z(`C_8Lx7^N>9Q2WS>|%NB!m!8^-}`t zC|WWo5$~!^WB}>wRS0PdS-Tk1xN^@Es^4r?kR_UAaHkJeWXnTf6E~byYK88X3YITX zo?P}5heS|zLCU4_Vv{I0V7r`(j`M48Cf6c8Ne&8Uz&xT2>q za?HQ*xPW>wZpl-c0YV9FL3DFR!d<5H7@}WhuxsBha(!jmPru4p3&&}vWZA~B&?l}C zX)$rJ5tgZeo2^cqWQ32v(1?Z%%*|de6WESaj;PaZw)^glbtnqUgxIr*y@0>Kwpw-G zDGe@R%#ZtL9ND1B@D6==<{O)eC8Qgy}qYxzx>D$riVOGrYa>l9@U(2x73X@;DYduW!Y~VbBp#YFrO^H z!3As5+Kh5pb;F~rTM-fCCx-{Vrc@>$A+o_jtKVd4`S)SzH>gh+!a2aFM)-$F?q$R; zPKb|vBhdX@Ek|VhT_+8i%&lr}RC?+3)(8CLi^63*MCWMTjVGB)mfWK8FncAZ<A6Jjq8+a`By%Z@vs)v%UXSUazEFE`lx!#yBMM)Gb$ z&Pq-T@rOI0c~}V#(pNSBTF_2&YT5Rs{M+rUAC;A&3xB5P3NwWAgPn}I(EL5bhpf67 zPxmn4caezxO2+TDc8lnEzoQ$=mgK8t>f|^7H^M!$H=ACR;&UQqAK;aZkh%3%5}2p@ z?OCAH{kPG*Kl!lxPQ!^^gJZ1ry!{9`+|5m(Pz+4cD+D9&g$f6Gc9U$P2*%z*8uTT@` zYD*IawgeEA<1m?7-k6=uye!CnGaI^ek2I9wchDo9HIF1A$S*@t!w3IA}8 z?AOadyNj@B#UK=qis6mee^y@po<0L!yWgG6x)YU5Tq_%z1y%Ud;4bN0u{dyS3Qk>! z%y55N>eDQRdyjlD@;vphR-+t&Xv$!qySI^nv14RY9;5bry|)81s(mwq?jPf}ALztWj=#-}<@TepYUwPhr9GuxlQdA|X{(e~G_)uWlGkk)TKLpG776xSby% zD`?f~!CO8rFS>shp6;%Lt*qS&3f5Tmi;CYZc0^I!4w~vBrNaYfDV^HExB$q)A(Y31 z=2+N1B}ZC_-4BTTFbRq(zLa;J9OU7Z@t-~9KNN5QcqVA+7| z#nFyGo1DJbYr?&r*Ics)m;TH@mvz%MblHusZb zR|!H#uKrS;UQ4R@YEMP%Wi9CAf6HMNB9s;OABGqZpmB6^l$`cq^ZtE8;Ky6&E&K6( z$Cbd!Z4%Rb!{EMTCwNX)0u0@RyB>nA)yUtSAp0HCv_FdA^7EZu%^9-=*%PXFLQPcJY~+}+3Tn!Sxg zlO~qEvFrtp*KgDJeZhb1fAf2DIri?P%D{0zu*Y*0Z@F~&jv zBMOeTX!XDwMuFpniE~y#jh2t>_RWXICCvGS{So5xB$2jaYP4V7LW&nkc|UvCenSeP zr48U*=C4%zhq$M;EF1%7#ux6&rhR!CFBifF)|K9v7(-#yk2v@HiHIjt+10D=c<^zn z`tr}DxVi2(O&g$LdE8P5Sr%PWu`mjbZ0PfSzxHUhaEuGH&s>*M3&+ou$}Rh(r!85b zE{8eUr=ztbw?l?{<~O7F-P`;F8V2tHfHi9IG^%9eK7`$Qq5eD+J_Q}ZKv66C4otOe zP@szGRvLwZeNfVygOL*H6=&KAv3ohM|Cta8$Ct6L?-h1%(|Mv0<4hZAv==a9+$;B2%I=`*fKj9)!|pHG-bEf6UEfe)zxot0oI%HA=?YF#^njS z^SbLP99S@dll!*kcH@Z_pEav^N&^)qHQXodpDpEDpOvpF%nh1T4VEz~*>9>L1lsR? z*2TA?!i+?N80jKO0DIsF?a86;nA>W?{dnp_F1d7pObb^r(PvGZ{(--l)F@7H1yI51td8-!e16Yp?Z3 zKU2bfKl-HY2eDWqm>mJjI)0lXza#&amuc-fcje3hAoo?BK8z&(3*hVbJW6k|5 zcoZr5+31PDDFFJ(91e2#Qx6b?C}kE88rbgdz^j&oW$>h(A*D#I(TXc^qKUve5W)TI zzk>sycdY}~M*dI5ofVDmk1IF7X6nw6T}K85J#B0naoa2iXUeo`B(OU^45o7C+&oSH z(Z2napi8iKj z8$0R2qA5J!bUlCiN&TOH#hyf~_)}Y*VaemUj7JdD?`!cWu)N$!6Fg$Awpzxzm8U1# zehkuas@OVYZ&Q2tOX$7Sy<;xJ!FtDd!?Se;3wVj`FHZ9!~j6p#d9tGKX}A}*4}1k;YpvTn0FmUX@9tSYGZos#bcr8 zv+Gb6Pc^&Uu}ziyf_2Vm%S;9f;k+zi;|{g{?yoQ55Ru_EWr6#%wcqC25~#@@W0L|KZ6eri#7i3h<$sjQjqr zcyQyvymvIe;WZK$SdqG(Dak_7Jdg&R0vbY>a3JDx(|7W4@6;KaBH_2JC)Q)X-;_)k zyd3w;an+5PGNJof#HD6Xd{?#d5cn2b^vNH_!WKzVV{b|EcWGRUUmyL$SY&42e0lH= zUz;&s^o!=^Jj#y}ezq9(j7j}M0gL{Ljg%Fl!vlK(Oo0t%bC%9ZjS`b{_-p7B9U&`t z9ZPSW?M+_a9uR2pqjw)Jk3CxQ^cO}lHXVqz<0{$;j!%LE>i|S2dv~%y0`MTfluC%% z>ltlkuq*sM56dWyAzmhG>a6)p+8ost;=-t{5U!+Jx+u3Q{I;q_N?||j=Io9Exm#bN zzY%I+8g+W%-;;e$trpAAc-uhZ3I@R1R-)> zk#CjGBBuf7fnQRJ9^5754Hd$pI`4pO&iB8&*qN5j5WDl_XtUjmS$D4W38hoWR(}}p zeP@##q#S&_bm8z_815pbafwgr|CgO$xaf<^LH5?K?6jX0W#F5S6~c4VCih3Ndw{T$6xDHWQV4qU%aDGHUKSjKgM>{|z~Tx?NZ@N&|m%r8x( z>OCPj89$=KIct6kHlEyPE-#?|E<&;(8z~U}w;0{1DRyZ1N`iZDGp}a?Yo6w@_M49K z0?vuuRh`rd7Eg=B2^f5pQP0*x+npXa3-1^Q5-EpkUd!27d(+km9Xl+!e^kA+-<~KD zk_0atGo-MPC+1cp=)A<8npwLQ*EC%DrO^!=)ZXVd^OjJb7P@inBDC3=tVg>TYqLWT zKvrnD53Kpe`5%HeT5l3$dQYwOON?C3f1n+qMcLPESrU5}S2EB}GijB)#q+boM+*z< ziR#aEdvRk#AcZNTC37N2G%2UH6U~q}-*mldIw!!lsYcFQv>24B(pt_geB@RB>uV!h z`vGm$SHbg++uz;G3w}=z$3dgRswSr`tlMf(VGF00eFKrADZ-U|Fm6EOk8FMb>}g7w z;<`#+Vx&UabUuTNgS&AA&0{gu?^jMOV>4I$1Tibn7aFfSCn7Y2Te|62MOHb?GB#c| zOgfk&N9y7@?6GY}*Yd5s>`!^|;c5j{3%LI*VeCIGA)SU@{+ko zi%LEJBjxR$9E6<8@?{Wt_9EcD#ZHU$QwKWB?WaH|`8*{ZjUDF=c@N8$Y$#xf&;g3| zWlpV1$Z@A^UBS!e54z^PObRan(XQ?w!J9ldeZg^pqcz%`gc?O6Vl!o?soXn+kI-k* zM~^WI!HPIuomu-OXMbMG5I4aX@T=4<1D+!;0DQfUo5-vqgeq2Am zLZPpmcvwz-u|aTIqNDpU^z}ogDOv~u2>K&owuz2l5vTp<(p3j-9Oxs?3K}(1>_mEU z$j`P;S}80Iyo0#3dctbur#F;#GVlDmK&HB!&z5}c00rgTM6xJ~J3;^H=gr~g!975K zvSyKD4-vsU4`BffAj^ax6^MRtz*&y2{v@Sek`sjS!7eQa;9!>Z^e4m9#P&(xiza({ zFV+I&(tcEc0mfI}C+57^5w*v4zs>nnPVBkwWfs#9upFs?I9OQc$@HJU5zF@mNQjcq zcj{;tnJ}l#lPPO}`-RM)v-mxHGru|AD!8^!iKV8$m1iI#S{X(65v+uO#leN_4uJAUr_dE51?TGui{u77g|&vQvPu6^@_L`)*j5ClL?|#+T7xD9ewd25oI}?&GWFg zpgNk(o!qW*wNOdW+`8$rKCPg`q>VPDmKTpD9!#Qcje!2Fh zl|Pv zzzQi0CfA*LBJWxW+ad(`-@z;jThLj5x;NbCHm5z*se;uher;f6TO*C8q*Pqlo?fm0 zr+v%b`tHBHWa3PHVozCymlutY{ul827knGzrm^E|-hf_^lO9(pDa-+J6+P*L>(YZh zTf2u>lKSHJw2=&BKzTT`qi)?0i5>qYZz|B97ID2C?e25i9X@gANw0%#<=qBdHs+r| zx^HO9Lr4!s(86F}IHw_=K%|BAXTa@+@kzF*BY z4x*XP0I-iBG^DFvi-cvHMkf7t-Yr(LTRit){SmhIwLRX`t!Q<$NY9AvC(tF|pYB20 zxIdIXG^T_A{ywBb;&a*}2s>QV=UPfNc>CSTGY$globGv2mr<{v zgui6w=$HA*JRby@=XZO%t!TqSGn7C-L7+PEPk+ z2i{^An&D=SXMxAFkx6Q*M%Ic4zxjBwzcV#{r=*Dpq`|M_m9U~h*;;SkfRj3UgMXjb zVH_M0j~;P7Jl>2y@2Py0Z2lm6K-SjxewEvR+Q{m}A9KUEGS~Gvj{KG3sifJ;z#;{g&oS z34f;ImE&T7F8*Wlt=BIR+VJMIJFZ`$uDvXkLuHB`(Ql8aPW?^<gXE{DeIsf1fyD4LSE@W82Nf& zI?_ZThyq54kt^_hB zNE}%riNPz+60axMy|Gz%SEHt1u2$1+I^cb%Q)^?@JC+_v`cW7c{cCj%^e!>$t>wwI zNZT~wxl^0l_?bfIS$RJ%W4fpRcC8c}i481-?q6o6x?)L1`yB=QVQzz$M~X^WP4J2< z^C+Hn8ci9O4R6uZ|rJPA{|!rMTfa@ABaz$74uCz@bQzercl6)?}ujWFq38 zzyP3;M62hy&kaTv*uI5ERV|iix}#r}jV-W%6o;_e1qfJz5+l;Ci9%+{B>Ymjcs8ou zZ{{-Nt>KI4a8v|A)a~X2PiHKIICi!qw)HOQ4}Ut;>|l=Ra;9jIOLKeX9Oy^!^f< zB>AnfJ8!9tXgs&Q;E{;l>3-=*>XhCCk{Wl@&+FUx>J7=`xDO)-_hQxJoBLpDzH|Zc zoxw4|jOwPP?+k6&zme||brq_kqp?GSJA1f2zOeuyT@JyeG6C_q^KUx;y{Tcd=PR9O zwJvQdzsmyT8#ef+AiOkKjiTm%Q|`9{RU{2W|NQScwMO5;kUN^EDmS^a)#PG*>dB;u zx9V+%#HAn!d=?uO0p~n3R82Dq+W;SY{2`x8v?kK7f+u_+j3i(G)w&-c)pa(yI-uC! zi65vFD=4?xuE2xfLf8%RHX9kS7elP68fj@$)^I=0S6jc-lp+<*o&%DEE4MusAMOQp zj_Ee7cVB$m|2T8qL5iH;%_GuwEc?1O6}orv1_{W~nhBS(bTz=rEO- z0a(hH+{#sIn)SSF9u$NtfmEcl+Gv)Qabd{tNL4L^~&NU{o4ViN%P4 zhjyzXZoQ!JEt!?O-Jl0=%cUl9y=(?SALISXu)Jk#F2WJVT7NG6mM{a6U~i9-*l5Mb zh3LW$W3K>*HqAcb+!t`cg9{e0@&3ys8I*Flcy0N1XW!r>`=kFPA|^Y0a{!c)F8b{? zlEd$0;Cf23Z-nzl^fCW4f>wr%KGTbetC&jf7Zm<(6V2$}MNxaJAxANnFrSgzOKxJpUu$E_0{QtE86cBUBW>f2jhriA5 z0Ic`&=oRknl@F(%H3%tfgD%antsIr~8)D*)88Ln`wziF#sn1s++kn)n*c|pot{aTd z6=JB+b9t|G0yUKwn_EIhJErh9c1iu}(awn?Z?pJBcJ*VK8V$E_a}GFH?j^zE-Q4^U z|DL}_ZiT9}QyU<-Q9-Qu;6AJTPn$OCCv#=FVf9Q)p0Cq2KkS#Awa~uvp2?_+qhxPp zq^12zi|F9Vj{mH(|zQi1zGix)`X#d#Q7;=jhC^Ua?> z1bq=i=@hC<{2=)tAsMiTdNn)8%PimCM#2LWEH!7?*Sp#9JD_KI{QhSV-*_XJfCK?> zI-Tkx!38(S-h9ZZn5#jm?kq-6^v~PCMH*X?j(xlVzuNYt-)tcH;bs_WZ~ke98_;%h z6yOra5&|0n=|gHl&7A&G_V2{*3LyJRX$l4=y%s*HtpnllcMfrO-oJQ0?K=m0pW`jx zqxnsO*)dqYo$5Nplk`uKY;TP$9^|p4&qUofQ1rB3x28Z+IbJ?1v?Xa*mJ~;tJ@=NF)0JL(>AW=wv@cYk>9^Q~_Hk8tkpn?9 z+yxbjvn?7(<~&HCTTFYjHe`psm#0<|?k37-Kxwd~RR|E2fR}hCieG7(?_|h`@@f&S(7f;G%5=$XU3HSx zu64gHQ@)7ZjX^H+3$9qKGwwvPo0_9C9?xvw^T|SlZxdy?v!03~8I@9$&h#OGowf>N zAE=X6iu}tYPHUSaS(aQ=k5k-9lp-+xh4#u)G~WO8@h^sUZK^T}S@YGGtC=m2#{841 z07+CRaTmClbS|`i8V;AYTtQUkZBCKF;Hq%P_wW7i#~pE1�hmf8C}X*9=%`8T4QS z1t7vA8kY=)%)Yi}3(#U2b1q;;$8PzAh3{POCD=ixK2$E09G z@B_BEKQ5wj0xUa^pA?}`*`XxIpg`wefS*2{#+=9FLt_Oj@ShR>lA@S|4^D(kNQKaF zutdI#EpA{c{w+^F-{pzU|MREbA{q{Z1#^cFuEk)2^+B|javT=(FdiYG9t$!_Idvy( z2mu3=80>MSWHWi8UTUQEornd-KoCc$PX7r|qQ95sA}b`;IUe`)rEEG=E&D@UIcqLc z>GVV`B%1YnxMT#4@ww>V!Q5;SuMl*LX4wG$)zKH6D^;E){V!gDJNfq#}t|C(@5y%`2w^(vb?S=$4En!%yE?^hNP>0I0icw}4s|NLeMIzFDrQ`t zm9~h_btZcrhp)A+UdEuvlE2CdgrmPCc`kpRQ+%C1E9Qug=9Frn^d5G!a+TQjj zW<&kYjx>G9ie(^#!kkT_T{`Fw^fP+AbjLOjeG_5Z8B-1TC=nk2+}HV94b?j_<13ay zA5$B0wL5-{kp;-HBC%qVRdhF@lBXB;azh zvTfGdlI7yHwWBTZa9lH&hqg1K`P)%PCnlS@&~8e&D^L@?j#Vvc$X3GgW-<}Q>t0xN z*G9hjY=ND4iHQ#J85wFrtH7$_*2AirxfDmUKZxN$zUnh@ne*=-2yWD~SAP&J+YdP( zudDKJ$l<{T5a|!U<5*#;IIhkr_x!cLw^RR*rmGBy>U-KO zu&{J@hjcg6ASECO(jC&Vgfz&~rF4fNEsfH(gdp81u}F#3Dj-P6d-3;w`NW64_sp4@ zGiT;G=g!k9a%iHuP}oxVK{DVV+7tJ!i{KE#N^t0#(JA)u!L@nCA?=|}994{wj?&2k z!iNS#9Rt*NBZ#{Xw3V@&eWzZ9$0}NZ^=&5Qmqj<%AFe_jBtblSwOhJfyW{1kfBZlH zelJg|G^jZ5uQ4)+`-JBS?vutR9iieN)|yKXV()J^S5=!d^=j7rFuT(Hwx~#3H5+wf zh!KEwi7j?{0~;Nw0wPJ^h3cp=Y8(0OQ0F4HPr)Xt`Q|?K*M2DDaN*CppZ5ei)DRPm zFY<&M5Qxe49ZtpVq50`2>t%P|YUTtZjri{3ebV^{=|j%iBXC@YY4&6vDQ&7yUOA5r zvsu}ShsvGp7t!d3%!F*TXDizNVU11#opn6>wS3k|WA*dH_`B;2c;LO;v%3|}URy?| zhy;Hr9r$i}uY*+&k}IenG*+Ctf&6PF$D7 zcb2NBJC}VgKM3&y0o94~MckXrkDL9AxcJ{u=3w_k#)DZ?V(CYTJ}1kXrwW%`rZs!xUCUl@hTN^D?%4C5aE2ip&CgU!Yg%<>i z8Vx_R1tldXM7Jiy#@g8yewhJ>J?OIa&fj}xI|9*-4(kTDA{lG(NLu#nU%ZYr1Jb-sZ+@`G-qgA5+?k~E6^MU`855(B``4_Lra|~?G z5e2%$O0^k%7`gox2Fz?$*bNRk1oD7~t9M*R@vmq%Ff0Z;KR%|^{D^d08vgvI)e0H7 zD6CJs?81|>;oneaam5P<9p3@Z8V{g;4U6a&V%7$duCmh|zDMy}su3KYr~oiXYRil* zbw%bomQ~hQ4N!NrC;qmU%QTh=un9>GhGm7Q|ClFzIMk&2Ab6YHCw#s_u!a$gmYv^s zT7tJsXQA@Gm0rL|-N8^^u5ul?xy;Ia)YrtbFRA-4W{#i~W1FG%Vs21A@fafrruEMr z=Oy+-UtYmX>ZCWqdi)&F2(FhpLUO6hM2iW~NX{S>eV`W&FXFrTE{d?wd2=U*FHM$t z_Z__W>06Kn%=h@}!5vNLkaim%Bgz+(0qxtxAar$yUP>Y{zjre&I5Fx4O>L7~;PV~k zxmn|KhfS=W0XD|q#p$xa%lmIGaZKIuYzS4jZ}U)?OLMg0jjO4l4vzEyqJxSBczuPL zhE)KwSuv6K!^9gCcg+!)^3^7`^0ne2=3gd$1zEM`0{XGjF>&k86@JK@a=46?M~wh=%tIX|L4qhp=us|zqI`qddlwU8ZwuDW&S?K zBi>GiBT*ZawD_2rg(_<>EpQAfB_2*AaIqJMpCRtioENC?PUvi}LnYG@x;4#5=oa7t z_`|f~IFQVlX#bQ=#oDi-PBnH0*M{LYtM$f#rl{xSz~;f3JzvnPh zE)WbR@i(oV*(Zi;EH-?UdnaPlM}%;iF7O3@jk^@T+q&ft_u&CWc$w^#<~sCC>-$Z> zjBy>vpUrIMo?RbJ8}zjq3)otPR*(x{Q&U(iE!!%wt#GGT>EdHWI;(ULHYHwUV0T=EYg&Eh27%5=;gO_Wx zn1CRVV(~HhqVHwfe?AzUY@sZLOoG=>2k&mQU=L`Z-BLRvxjI}%L?5O&i!Ys|@))S^ zHGF}KvFO1B^_AJ-W*!AE@b32%^{DgLEKz=ZQhyLR8vGlTyFX)ap7y~n+|2M%?=d~p zJ}F*DRS!0CnF%(GVk|0`g;6f5INWi3EG7_QF~e8w$+zX86v5gg^z%EsI>#jf}A8oxS5?V@v69T+u8D^iy=aA8Ok! z)rM5ojp^_FMP(fu+NhOHNX1I#kbVCc?#7`eI)5zv1Hc{ChY#Znb!C13`IqvBVP$G5 zng@dHt!Xv%l0GQxT@<&I+KrpBa>CERnIz|r52IuZ7!{7*M+8niB>Iy~t;9>G`}znC zIJa{O$>T6pIw1#6QXKA|nKN^a5WpGE5vcr% z4Em|s@%(-lP6kyNmzx~$`%g1*TO(^+Hvc7v?l}5e9av)9cz%}HPd>IuE~4B!^YZ4L zzrW*?gj0s#KM3?DtT9nN!}ebsVwOq0L=}6X-YghQbcMGeaO&z!ImS|2iLd{1IX`&J z6~Q7eAM_D0oynKR=&8YOn(zN=H19ra=P(bHP0ZY;@3nrYa*dhs(;p8^o9|qi6ClR^ zDA_eKM!>RhqvW9gF=%Z>X-_;vRxb<1jCqI z0yJ%yfZG8Q<^dbn+Je@G^{h1Pz?)5rh88T~K@1(z>-d)?Mno%Ly&uupH2)m4sQuyC7?)smF< zIxJ3-lv1e}#*8xndv0!Ni`>i9{&79JM9%@l_3u6?H?Va$eHUtX3`~jg2ks{m4Vvi> za6Z5~zczeKpYcIikXndQ+^?6m@cJ;17%s`#QwKyRQi^lPI@`u7HL9@!{a1>=%r~&P z<%dyVt4Iw=^_TfkD=)0GM7B&|D``dh+h)aDcYa4!LviBaP(yLJ;3^oOL@@a4YGO`S zAxfsrmCKX z2p<{zRJaC44`q#=Y5jU72m4M$G5ky222#jMWFz^!%3o>ztaJ7AcW*@?um+|aU!&G9 zg~;i=p;)}!#>=V){lFE$5H97Y1ER^7sL1n9NGD$cj2{hW7HOmg${0dkSSg=Ip6#e2 zAEk~Dn0`A7?1Eavii@n*cR#!k!-&=+J6OZe>NV9sst$O;nHms~YKM9EDooOUEHh&p zZ}SrEKL_JkA=+K5J;bcV$!X4L5GeX%OX z9%q)XOr^|h7O-+j^h4=wjIKX-marU0@7nN>0%|3q5j#DeTP;^2urv09>QNUP&>X45 zD%`>Jpq`gJH$j(Lo)iM6roaiq6QKf_i+P(eFB9Oq#*AhGHaSUuebJ4GKkPs~#wF!| z`y#psE+N})Kj5_~-kgI_t>NPxV6O$4vr4@{b(fRdr?j&E)RmR>SU4R~>r}UG_Ml)i z27#IV3L~wDx2{-Ap8pa!^BzN!wdsB}67=RGex0nuCK=F#kOXDXGQOFDuUk|2=E7l<)-{c*j>1^hx-nbAlV4(Kz>cajWaCbE?iwNbZ2Ch9!L3g9bs&VwaM06)ji}$GQ6m6D03#UV79$)V-6u%K?Xx)mx-jqF1u>$&@%*k9NTwEo5shwTN2s!+ zSck^M5E-)JOP)e7k5MyT%~)5S-1oEsHRWS$x-f%3ZT8~kC1zMHyaFal(Q#z5&&)pX*m#29)#P1>@s$xe<2M1ewC_3jE75i&bST4SX*qEEOQktR zVDD)uNy4oqEvyJ69#;`WzF5M`?4Ueyin%Lj_)Y2R9PNnu*gV!mZ8?p?q8&f7!@VVO zGKL#~2o)(AqT>QKrtUhhSiHohXkwBu{$aU*Rd`a{@Y8s9h;Z*C{=UObMJ>eWamB?9 zC!-*rW!b&OLUK5&6Q}&u+~HipS-qDF+NZNO)IYtOTCLC?nb%~KVP$2CqGYB6Rbl58 zF;}v3#9qIDUwLUUrav8&!NH8m9LuPj%!-N%8-F4Y9&Yv+i!*J5ZNyHfyD)Up;*{Yq z5?wRL>&N)%nY8M+@tp1@i=flyMZY@}J<7-L8_LiO{1o-(jr7IA)|NH*71@aJgD3$e z278Ku8XL;pDB{+}PdJ=i-7PCnr}%#I-h`}6Wn+Cze#cmRL|X+JJgy9x;&r9-Ei}G0 zlCi78dP%zoH z3O__Ko^8G@8eh&Qqd;xU(_uzWC_m&GK|#w912#baG~Bd1=Cs@`b+9itiMDSDS1&_u z>9U;s$}f6^kPH}PvXBPf&nGOKKh8BTR9vNdb_-)HFgLF;{}>IlqYZ{v{N%iP0?s!D zRb=(GNpGt&wdzv#qleuq{50JZQYU1Om8Xa-=9*sT_=|Jp6dmbCfwbiwH!ma`ya`G! z)Gp%5+fLtO(v%ceAWW_ODl)J7bom9)p)|{UBGyTmgGQ3tW8+5S!q?Zg$?wzxpze76 z6QC|inaC60zPw3W&GdY>%@^_)awf^9y;g?VW8$T_CGu_G4EE|;xiZD}dC%=7_|5RP zXKr5J$|olhfUJS?_08AK%KCa$0;`zPS&&1z{DPx5zs7p%x*=t*5>Epz(8*c!DCLCk zNfAyz;Uf`>GO}Ud+pK4kI>Ns}a`X7)yE1e4ksK)ro`bxyc(>%0$(`Jgk%5-2dkI*_ z89DTXU3TOOiv%ix-&;}9%tnj<(Q{jcoZn(xPg~|QzzC7LQKty@#@-qu*&6qvJOOFg z-^rGkvrG?LhF?^J-mS6$F*^gj zK+iUDw3!E6LmKfWntP}%lIsYgQNNvVL1MPbd7%TO9fDNTQ}B5%ZSg;FpR$!dB~`BG zZSAk=-^zUr@3F>yB~K-QS%qMPsOx%6n|ShVRfodc-}U4ZWn>sFrYxlCVpq(mzkK-! zFt9YhEoU|SmQF-e^ii`DQ4t@m_Nnm5Xmn5_*r4X1TM5J@m4sB5gWt8+e=86|8{3tA zFR}Uhb%-p(T!ps7x4}5{2n8|swOF^yUV#|Pfv@IB-vo7Rqb;9{xU{Xtq&1x!gQc?k@Syq)d)SrRAy-u#Kn(9)9uli2hp^{cMFjo3Q zyaJ--S3jq!uErO3^xvvf^}Na**s_|he6E=*5=STH%lcWv#*%cgMd3^I&p$dl#D;3t zIwdgn^u4Trsc%{Tydu28a@lv?k>_APEhq3BHV5W2!}tktP5XT<(`!SPkS+UFk8DL@ zD83GdpCKWJ{6Sn>{WViSMM2Em@xi5amj%D=P-5S%S0liy3RqaLX>^@FT-428K1UZ~ z5fj^~M6|><_P2L0IL6rUUhb*t3;G4;P}US#fOqb#jj@uF(m>ePCGr@3x`r_V z;eDue0cmL!X zPp=A18eSEqaZ<;4j%FzNRy!DTADs1mZ3DzGd3Yh@dt?N3y$QIxSkhZO@}=2uib0Lx zoH9U=ri2Ozy8XzKvye?n3cWMceEfU4B$|g7Z>)(@&<0&uS-Iwi37X(`mV>Cc zY357#^t>GOAELkLxaR?5B#5jlKc7ISMwFJ8J}!XdEBBcJ;KGmj_-vt z;$|)p`J?)C)#q0F#4w_o6GjeHZS!KKY~-xi3s7A>VyeTM`n;qKdrq*1cl6}xA-3Ws zQvX}_CHTdk*iweTAM;gaukS86dn2PIZtZELduTdry)+`kY8=BY-J2+Vf2`ztPfGer z7nT;5G&Q9Lob3sE?~Rwz&0!QeMdgY2n=;Qv^}#R}IorkzwL1S_f^W5K7(8g1^7k5r zkJL+(R2ruZ%ou9k*Gyg8NK$_ugGb2gJlM>F$k-ti>#$AI>XF=2fYZ)=4UMSeE5pPyO2Sl;Jd9T zd|P$PuUIXyK1{7nXzt#sRT*^;@h=?eW9{PWeTrd_5-@fKMa00h!}Svn&zgByoVicb zT^~cjr)lCHYzoewzX)~q;^8Wz6m=%uFYu#}imIC0UUnKVH$^myrO~=^G_gAl9=n7} z?CzvV{v0Ine5|K8Q1j_iIu2i37(hAn=x&++lhP|RpE%XXM zu=z;eM&~#ZzKDy~gL?Z|BFQ-9Zu|D-Cp2+1mz^Q({^z^G&fi9ihH0~i5C4Sz`t>VY zCP-|qTuWn2zZS1Q_3`o+gUL@mY{<}7-1-nI9&}cnz3ho}uivvWiLFSIZ0P{6*(ADI zWH6fRNoLz4CiWS40(^bLVeq3iA&d{A$bjS>R{2QUhSS6xFvwuL`TutT;wY|Ib1}p9 z&4{yAEz#JQ*z3yl0o%}8Uwr3b7jh!^eXc$_B^vO{?wQQRd}!9?4;(?n)EnfQ>~|`~ zMMD~+75uSF`m2>c`|sZQT%Hl=nwX3#Q<$fx+V+wN#GTyQC{uVPt;5$_?6Z8L{wbm- z;hef3JCs0L+1F0d50wGqbyGGH3tsHwEwin zCnV&EI1vv-<7tdFD~qnR;EDO*(H*+DQ2yOOKSbTTf9E+wl}INgwwuQcv}CB#t0+IZ zS_pdcwTE$skjW}ex8_S$s&n|m_}6c=grVFGsYgb0TvpQ1wCH!>>hI03YdolU;ckrT z#^_s6e#34D(t_QLgPeTc1b`T)Vt)NPLgdL-UqSi#suh0~-BLq4=HCs7Ox(=Pn)lS_ z{j;*&+l-71fS8#5(QxRTN6mL@(+yK52Y;-qT0bh#0k*<}3GRkmgo^8Dks4N(62$*;!-FIZr~ctmRX2 z%Z(qA3v^22!oA7DK4^ZN6H>Ee{}i68q9EErw(aM5!rti|&u#TdtnRSY#?$1==Bp>T{JO2}Up95fawnKeIdJUiC`Ms%U$B{Q1n z*P=>6cF>KfR|Uvb%y_%Z%*=1TopZjgGjwE&s*%N7&ckg(D#5 zJY=-V#NTpd97EqW$~u^m>#_?d4e*ZcUG{OkB`~0SEGAQ*D}j_oswSJeS%2wWay^DU zD$voJkYGxxa(W%#r%zd`Hn`*aJ~)caRc9rSUS`S2xun2_DLE}oAq|Z>c7T^ zs6TUMxZ7#SY^RQ-$$Ievq&WtFF&Y)?Iru zQo~hu(x3c@FoGg)ym#&Z6^|_~=!5dw*7vsq2@`CR8&>aSA>3aXuVBxC?CsODQyqt| zRmW?5c=gQ+8c#NCnW|&alC00#>Zz+l86nKmV5W;U+O9gp4Sa|v^wa^=>U`za5dX16 z|DHbY#9XC2JP)?+Wf)aF`Wp_jvzc)W^k!de(PB-NeAVnjAQFj@l;ATT?I(q3Rw_Ni zMMoX9IY@XmYeIruCN|N5;Vfn4fa1DhPu3Kp5BCTb^?CZAH>=@HIyAUlVaC(I%#GLP zZ4g3;KFT%9u1HUq#)cf5<3u&QfU#LUs#w)*z#9+qhq|AiU&ZC^Pyf}a00Gl*qybH( z!u#p3%t&1vANqd#R);Bi<`lKn8h{(RqeIv7YI~i~^@Khj>pn8S6x=o!eepk6o_%T| z`h0B981XtRnuh_64Rv#1k7#T!t*@OldY`H!r#@OB{hi1*gySgdpF-@de^#&=Ny8W zfYwOEq|#}YyoXr-f(I2`PYHd(20xTa}9x7~J z^~|w$r8`I*;JA7^){MEmXZ$uHuQS>Bw{srb0mgsRWUt4NLlO?9Zlt1V`J#S=F_ajS z<_=ScjDy*}tdmA#*Agwy;=v-GXoZBxyn6M@NwRk_x1;0nV=3W0)hZ_E(eck-W^2dT z@M<^JzmqupUCCmwjrsXOfWmIh_l`Rkm=%=+b$rS!-oMz?glZ|e{?uCzYWOzR2fTw; z;WE)3HxXsip4P7eUu>wwG*k2H-y)ynLh`z2 zm&1MIYm1xh#gBz5{@05OpAYMM3m0XVSMY8yo~wj1u~WgmDgFO=7#?`Qcr;L)oy5GX z{=tfy^5 zPT>FZGlibT-nEe1#8m#e*uoC-&9GSO5<8PtYDTUJeh7e z&VTn9Hh|M+Xb})qSXh{zZ|S0CYswH$jv0$UVT~kk5E~rrOY1~>URtT`I8;NJ!Q@xnICYST z0d{lde}Of~zKXiv{0q*da_D8K-l5KGu;Njs*5q}d~?4e&$ZY&XVp;qa+G_cf{|fb0&I8lp4Z zRe#Qe933f>HP_Yg0hGrei-6sXQX}Ke&dz}Ag9_sgAE(hn=w(cu(MkIy2b@9p@{^pK zWupxkAjG6iRy+OiQF%^Xp4c8BFkB>g-A+NRqNo}N&e9o3@zKoEQrpFa8_32U%4`YRyFA^9K1P7L zb}jVg*mbQ%{){OzOrdPmK1 z9sxz)%0ORQ1ZsCV$QK{(-yLvf-{QXhRDjZMJX`Q8Se9qZCsOxE$fcf(mH_1rK%~3V zb91s?7<6JimdR^8$IedCmrslw{h|Hk*)JGL*owHO^)Q~ElTn+o*BL~Kpuz{nXh(5E zEiz47F#JYP3kUhi3RkzsfKc~sEz|1oE+U?cdl?A%o7ao2l^;IXTp_oBxWIyaW+k9z zZce9>$+HEFSJK!hSbg)zu=~9mqdh^*-B17ghXvib5txvhOD%hrGX?z?$F6H;rWqP4 ziyspKmC*F_69-7K0hZ(jp95Vn*X86_cQcgHP}-jp#7$HLP(CPbt|fZ4|Ei%@wNJvo zx+8JhL`6V4>8slWK9H@r5*>sm7byB{54{OKcCp;9ZQc0RkHc@bH=dK8nW<}F5dHNS zgOLz2y}J4o2q@JCwcpzJ3%9E(3P~Uzg)b6?FC*{trOT{3 zb#JLB4%8gu8B5V=Ab0{Y+Ytn^UjSa*@%bvf906-oK+KY&BA}i4@$vD|T6-F>Ix9Tb_@FC>)q}#z-=Cgft!69Iip6TyMoFRrKr7_$S1z4Qk)wKY~aWE8$d3 zbwUib@3hcF!|N@pcv?i0*W3?h&?9$_)CGJLmhPcrOF|4RdW0}MB=fUFL>3~AkLcfP zJb}!2H9jWYGoT*SKg%6H?dPL7{wD3w#!Yr6riH`F#+*7>=OFb4!bZQz%PnUO-9p(z zX|+DvMwqFnXZ_FB{*1*I1!(oXg6lG}bu&XkD#r0_&q^8a_u5cdj=YG#nxipWsZX)f zR~(55{H&9OP_OXgZ_xDfsq&^3nf^Z|_yVYnx}DG+C8J~|xVSg% zeYjwNK&Q?%s#Oh6Ir*M1xlc@Z+#h5LQ?NFje3|&e3Q&}*MCtjkwP8i(fL=YgYyJ-h z=@|SYJp^h+rHGfHh=l1Kg(n$4l|#Y3?5DIm=~UMK5;GUwKqh0^x1*S5tMD`gq6A@p z$|41z%9YqZ%l@;6ji<%uFHdrswI5!=8b`%G&J|vjYLu9xtRoA#?z8Qy+D#UJvR$u1 zC*Vd&I?BU@tHlQDok7m&kj<4!{ab~lk<-$nVee23t%yq?;mPQvL$x=hsl^39S1YVc zQq&2v4h;-r!nb4khR0&|y7P@tD$>Kr&)NliI5B!kxBkMVC$o4?|7{VePoeaWOwP~{ zIANqw#F4CeC$NvvN@cd+fA`rDjp;!_a zJg4t5;v&F)ur4KIF<1QbEjvJOr%1Uc0;QypxEL`$4bdm5Z zQKE!!l8$e80i6kks`9=atL<~kmCkp?8Kr*$U8_Usqo{kZ%rHsSk|2uC)7j&j@2G`+ zvKqX(y`_R~inEgmyj2wr2#xO~NQ2#J6VI9K6&3vD!0>%oP;-n1s=j}j#y=&UYvmhm zDS3+`c{O6lDMiB~eHmbEGnAZW3f*L`Ydz%eyupl^2tCM+o|Gh4T-7HF#yAFl? z!3)m6=?HXE*5#s=o_E}*;z=;MA7&ub8NW<_m`&}^%mmJVK>Slzfe#Q*O zze0l=JJSD|eWWPwtM~`!*Y|5%vybOQaObSW1@!X6b4WMroFbxG`aGLrCdu zUA^xMDR9T(lAb0DzmTyaXgbWZ#M+b~SJ9w;uJ9cPn-VV{M7k*ug@+?P$Ggs4O0!}} z7RmDniiKY*fphgpKz*>C(e7y8AE0!*cI; z$@&~{wDAqrTsvJj&~uW7FMf$Eo$bq$lP46Cmjn{2+vpKjs;t#det@x|W42BNP1@Gz&t&nz)}z)7_;KFWRyW~T6gWRzJEO167STmC zq;JWFr=Z43y&Uz8O+=&7@j@mc)14^wjS&E{Xk5*Z+N1WOPAc&1hbOP6RfIRnW}88N zQr1lN0Uu}MUu}7o(;60+%D*4P+x}G~h3j&+vc5P%e^svzoe+dNQ;~kTBZ>4W3bWCC zTZCP<;x%V)Qf3<#$+&~<={8z_=fu9&i(|6gK65hSes%Jq z%`UyM3mfxfzmpDmsD<>=_}yIpC45Y!-(k4_$cAP7B@;V@iV3wVYVY;)+X2G@lDFdj zg27vrhS5ku)Ls<60XsZ0bf%bTc~f))k^YFUTeXEpZ){t_l5ivH8E_~P30r?F5q-2a zr?_?JzAYmPH-_@7N@@N98lDcU3|O}XIX*fgiR7XGdx_##oq{Cf+`2vO8{2l+7s)@lXS&wW86R3)VI?)FF7NzdD;R+%;dn6JecolQ1Ii*iu%#? zqG3t{zv&@%jw3Q_ApL=@d#!L6Huy-H&W^~>eLyLnk(TKBpmY#7g?qVbhqBsG#3P6z z2IR%_V#I40e;hCpaO{!Wk2JxNZow>cW8>DnD|`+yOpHiSQ7kh|H9OA?VKV9=$ei!v zUO$jJMW@IYr=4W5Hd`6qQ8x#i+sg)iI&<4vukxhhAwBhaYelvTPYSEI8U^4>f!Nq( z9fru)Vgn3*@E<6VbFNXZPzDN+6SjyN>})~Jn!P(F!WgY}mw!9B4s(?r<6RKU`8Hp*w(-bD}lu6crrt$3&FvKv$a- z^*P7yuqCF(wEk%((wJ^0{}1$kS0FS&MY5mccA`z8uJri^_!LQz1Y`<@dNq4!eT&m{ z5uyc1JDD2y2y-UKM5Wgr4k_V6?1|_7o>9<1$$Sfpm-Om?*-HHiWq%QD)RXVDOEY^S zJP|HE&X3Ff?SRQR2^RsR&J#;v48pOz``ES$M~Uzal%pRoN80FiYcrTNi zA(Qh!IlX@c-iCY3y$cL)Yp2jQ9&?f-%J?%>5o?@_I3a**P}7i9%umUU!u2RzMqzmx z?@&qg{wBx5mWp93>UqH4W(moChOVFDhyC4bF?B+>@qF55rVmVoS2?v4<=1_v3f5lq z5~LEmB+gq+z? z%ihR&YZqaDaqz?$)mtUj&}6Hn)BEoc;0~dCU)IPr7N+TS{4?C3g5=Z4;H-ecGxNP0 zrKkaTt_R`W3g6@NYPR^m^kDawJo*FqI(uS#(=2D2E43uV z%?)SydpGz20YXB*S1_@T+CuM__g`Q()p6S;lFVw`5^lIfS@E>zDcsZ^lG~Sz91C~{ zzO*@8KNgTWUU+4n{~JLXlYxfjv7_lj*=Oq5 z9}i`FP)56Sz6+6b;_CG4Fxk*lUq6$Z$1D$-aD0(?3q)o~*$PJo^@5b2fpMfi`yFIpwGnp&DGF=Vnf&v!++lvs8JHKwfu&s8KR zqP&l55={_5@m|U7ZQdFCI~GY{AFjTsHp`(H?H1d zvR`g(5tQ}ZGm1QNjcuLArH}Gc)GYU8-(cJ6?>uRdC_au0#i*t6(~Z6Y8WxPmblmxe zAo=B~=Sc(a9!L&th@jI)-2HYttbC^z9lsTLi>p`a)NHiDA&@dO%<(Vu)v zaiXcQ-q!MJWHt(F6A&4Y#B0JHTPYY#V_S7Yv_XswO9Qd(+A~gU5~U?7n43A$K)7oi zH}CPpv*5wZWitgrbOlC1OEC;4($m)I8njSUoTPRfJwa7DvCw_hzL?La*dcnBI3PdP%2NzGz=|5lb!OH%1dQcF~N?R;U10|R7q zE1Sbt{)e+1g~yx*#bGn@e;M0Z@mw)_-b@JhI5RU`?dp!#`KgFB)-sU_k2n~#_8-1! zXd?R!*8IKN7W)dAl{KVTuuS`gC};zX2h`)JFp+Tx;p70z=Dsgi31bh#@DP1|Dzt%7 zhZ%}3vTp?t!daxT>riqKNAN*LRIGufvu}SO0zxT}Bx^NDnTyjphs*?Wy4_1S4@R~; z8?2>YN{Jxvwj4dvy!>rJ8pSbO!@}0%g|7|+EZRs5sIQp z&F6YcXj6v~JbOLPxdZxZ?lfqNl1rFr2xDaT3T8^m zb0MRAu49>f&qqCB3F}Q&UR_!o3U4T;+i((m_ojf2jo(=V!~bEn$l|a)t9Lc~Vr(yt zO+;E5cqS>dK1Y0;B|V4=3$I9j|9f=xvYt+Q0UfprKcW3`4YZK}EIA_o;GlM&a*j-h zZA6z|Auvc^|KwxwNhec~g0e%Y1^DvFxvb0(N`j79{rEW8W;zEE&jS#z!u8bI9)@MQ z#QJQVw8?5Eh3%P0^Tz`gGcCerbPwW}Wd9iERAmfw9+*Hob0MIsuO+?tR8EzhPop76 zukxH-yC@lVFq{vluT0+z&G#KqqGx?nbx9*UQRAspE-}Ko#rQtDn6P4L+AWF>@Xs;e zv9+6-CpC&iZnG7?b$qZd)6#TydyS~i3%?e6#3?+Bx9ybzFCGKw{+NA{K;8)%r=xRc zxaFkf)CSA=lC>ARu^DfCZ#ZiVNovGHCJE-4V5?omOyBt(g=h(^GE9wq(fR*(0Vrx% zJ~?6}p?Zf++235f7a)(8k(nk83#K4#*Xjz4qluSBr1}FgTub(J-7|E*Fueb(t?*rR zM&byMw)xZQV+0X`AIEvcvyK0if*=%QBngy+rtSDq0b2ShJ!%w7$%e3Ura{&tr>o;% z+}m4NkwwrUB)nD_tEp=H*1y*CSC%==_?$cuq|tNc%eaDN!R7=<4z3rbo>Gkk`k@Ch zPXo=I2HN_PkP0v9{pk>&2AlXG{l%}EYng16H1lXFZu%RzQSg|)CsOy3CghzuhcK27 z=^}jP3rR-T1Xgi|ca)0fSU>rgBATx2E~1Ln4d-1Y81@8@r*&-m>StW@d;cPfT@v0Z z73V~L^M|MG*t>)NhP}Cu-E8`zv^@q}dR?u{^P5*{^y1$U^OvjSW9>Gn5MqumTijG- zn!gtpEfUTzy4oEvT0y--NAL=4oGW%DJL0jG7#fdT1wdYaDtP9EpZoamr3K4;!n#VE zREDt;aEVL=9562y-t`Doi^(woK8o+(IS@IHZc8{%I7>Lg=JLH*$eH^kh7bkfIYK|# zp-+HdoF`mQ!%7!K+F3M<1AbPe!bF=}8SQ3nFZ>;CE{(w-bAo}EudvHTw6BD2tOaTm zKNp6j?rxtHev_emOxCO#5GndO`GU-|AFj0VvL=OH=K&lse%l)D-wg8P|JpCEHIF2csq|T8>`lstP(*|MK5Xx2l5MIwX z&LesbA1aqlz*i}62Sr7q6JG_}Qn((#c-N7wV&C5qSS731{0jO#mLWkH&h6qeLS^ZGV)-J4B4{Ejt7QE}N9TNY;? ze*H~A>VHxqz;|daxV#mU;f8#MS>qgIZtd7Qx0LC3yN4z)0@jP^Q-35-0(r&}y+w~S zvC-FNzZoEF>dPBth@e~F3($gW$-r$$6Q*5Fbb`JMRmIqh_@pmtE+A7_#k~oj!?&vg z?9n$U10T(bPSH>1r};c0{?!HOhN8ZX^i$4PxI^)U39}QZ_NXKH zrVTd#{PhDug1H)22ETJ$ z_XK+cxHRle5T?Gt-3m{(0j?(Duc4*yet+bHaz8aIeQ>b-qL+jrtnaGbLTJ5!ZkP-9uuShJTV#`tSC=mr_m!ul8;wgS&FaqTYEqGS7E~x6A1kxY+E7;QBRqw_9aRe747-p-&cM6Pt)DcC>sk; zMLZ90C?>z9azSz`gt7BFw;*8kPeM7X;#4=^Bf|eQ&(rCcxyH2t0=9rLu|Ee${IVp&^4W$?4j@mWGv1l?Wy?JdI&*?PWM zq&94JI%0s~ciGcjc4pRuZAzS>vajj7Lp#Iu^C8j-zdn9pFCP0NgOsrpmHE{IsZxAM zQ1D5=POo7nYG_KdvyIrJu*ZB@M%0#1{fU2-AGnL~)tqfJ=4|`xNnM9dPX8n8%q0%( zRf2s3roRREq+YIv&9}ody-!X^*`r8NHcH_|O4av0o-iD)5S=aI1i7r2f&c5iEds#_L|G!)}IP5s5C!KqPn~Y z0SP}FmQD76Z-*I|t*}hO+_2rLOtWb{3lS2CbJmF&YQ2%Yl%Ci#xO7_Svm92>m7z`( z;JoZ5^JLVEG2nj4tYQN;1JVuAt6rS<3fs6?G;4ohdgYy*g%1xoJvmA%N(QInW*&T> zeExS``uMkl#0NAr3B-<8BGj(tV?0FGGwx!ek7H)fbo>nB>lp>$|0GKd;^?QJ22NZ0 zdang?+j-lZS;sjA%O=aos2lSS{JdXh#9cGi9E!MKFW@!op)J%Uy`m9(J)=f>C|tK1 z2*Ky!YE&SJ&&$4l3+&-_c6Eq#oI2j@>;Vc`@HbS`%g@!dU_FNaCid9_bqJk@j z46qc{zPv;MJbYnq)nhOns=-zOC*W;6jbGi+E=+I`&>e^o^gMc}IkTs58rdOM(ljg- zw}-v1QbXWP(|Q&BGk`eqFM*Yye=XkMRg}vG8XPB&KWmUS*Tlx$tRTjzl#o38o3Z{^ zPqg0r-VNF^e06K8Bxed@sE#~S$-X)-e!{rbH%~6u-^K0>v?nAYA9TmDPw!t2uZi1T zf^UA>TkXnKig|Srqv`-n43`5rupT7$0#wA4mP^&S`=>-7-oF^I&DQzk%7h{PLFE3R zwpdF=?;kST0`8Yq;o3g=+fGYzAl6_u{Ks{}^2VZLw@6vOD%=ue$=Gf!M(zK6fTF(U zr5}ShKCOJASe$1aNEV!K`?Sl>HU9!Jt;f$ZQIi^ zPaBmWIscb4cbH4i;f$|9Ux22<85hvAUB&jp=iolW|10k*_?mpfH847cbc1wvw@QbA zq;!Ym=#BvbQi@2AQo2K=VRR3rn~{?cMo0+4ng8=UpW?h9;C=TzyYK6c>y9Z+npbcA zo?cNuS8x3(lB4Z~t%}CPPINY{(T|}}LJz@{+dO@)HtWgj`J?RHA5)FB5lO!&%^$fqEsbS`@s(RvnRvx@WCXv0*4VfY-@WMGY#YdGOVJZV zZH@ozkUl$JrBd?L0dm4sa}s;^ZNNG=#QFCX&rJ|bSQn{+nXP8Y-iq6v-tgW2q>ohH zlZR!@30k<|l#|Ue>0AEJtzW>K6LP6iLe2H|-sM*75AoaIDa50@gmE8SHsu++fZ6&G z|7|&3xst6Rhj$l)4(adDSm-iizx+avsQkQ~qGGUzzvz2OaM5>8K_J!o)_$7%!q2BDK6uv!=`dK_}F!Ps6BE(%T*uFxjq6i>T&lYY)=Xn$6 zvAKvF3RBLYIHN|sX&M|aPdNjadG@#Y%)RSHj8`md89?Hcyy4SV zk-s{Euys7v*1VY8>)hpOd$9RBngZZ%N9>}FU(3|MBrt*<1`wD?7DQ~;v-D`G9Is@yD)cTL24%j*N`eK9v$LD8Qz_8M50IM1yI{tf`{)(0=?}$* z;v%s&A&p%ajzHh*MJ=Jm!(~Y*=l1ONNPSjFN@@7(e)f%Gwm3^_3yiO__<|Axr>*_G zmX|!Rz1^^zHK{fS^5je4!^@hsxcmrI4qVO*XO-+^6KE4h+#@?bSWYF=jOcOoP!0~9 zd_68Z@I6=k{M+O87!(mp!!E?3cvKL>0q-2Qdv|U6c}x!Z`M~h=YcRL0%#&QyU}8u9 z37iIw4#GB^bO6V!ABN(KGn`Ek7Lk7Z17$l@2pxkeRL4S`LyXC}4F*EBfnw(9)`qzw zQMCZ+@Aoa3D7On}BZoBoNcBFF76cp?=jWc3T)4q)AP55eAS}QxV~_pQPHplxtcmNa zaKY(}Hc^Soh41C5>5^qxrcdRFL;SUL$_J`Gf!!)8FWkQ7-ynqX(hmZ>FXR@Yqzdws zI{f0EQ%dOZ(HdBwUu@}5PkKC%K6aw^FQ4?Z!Y=np?QK4dTpDnkIIqP$TYEjc+Rt$p zqD$V7#~a*~CqC)HhsfxuAww|3r|}CkzDePHPt^LP@j>PZ3-mALee>pa7^9UK=LZHy z7klU?x!fLww}697F+c8$IK0WBFXSeG$0QBLtY1r95gG|hx5k8%^Cw%x#Smc>I|b0u z{RnLV_qyKnXS7uEzdOGXgODWQ;p_CjUeLwnK<|NMV}9~J;M4x(%d5?ne<7Ws)wL?4 z=WP0`+`yRkM}yx-TG^U_nEtGf6Sqk;|{iwEEx=EIYfg|wOUTi@{C_p z`&`7zZS3Z!HP*CnOgosX#4+vnXX(Y**Xi+o^e8IbN1R!~wfU@u#swVkgy}X8qC&s* zH+SQ@cw>wp28d?iUq!eAh<-UQd-Q3Pa+nM)$+fw0Vv2uVL9WWU;Py*$3><&n#b5lZ zA;2o(r&`P#2JZ#8ksJl&24GEe3pEc0kyRdtQX2yv8GNq<%Q~qb81&OniD9}ZS$7;(JcLP$3{s|*t3QSzo?(pWwgLzRL!FEm9q=@xYZ`FHDO?h%KU zIxa;x=5hoRsTcl^5?qPtU$Mh92mDPIX0l>F-LDhr(3f zEk{lEkJw6r@}u`Q4mYxhehtWp6YjKJ`~N9aV=sXN;gS1`SBji3S(v7?qBcLQg^7hn z7=jfs9uKO^lvJ_*+|D)XP zSLnYR7!s+jJs77>kIEXCZIH?9;q%k8ekqX36fs>XC(k+KB{;y0@EowboyYtbj%4RJ zI3OfSiZTUc1FZ}}Q}<>8L?!ZI9{h~6qE4QH*;O7muZ!`mtHU9wNPJrx!HdkT>SA80 z_nSpyfI2{zX_t-y@W!DiF(r5&6DI`9YfNG#7PDzvGgUa`@RAAF5sFb7gy%A5s5WJ- zC5v49nA7Fr76(WNlL>oA`i`b1w{-U$aM_=^5-6FEzFxAVY-4~oYTt)Me5MS2&f?ZJ z=RoyQ#SN2j6L9SrlhWO=oZ?5Fb)}_BYvTE1KfZj1tXm7Zub(@^u0kXoskdgyQE69n3~Veqy) zwlS;*{YGWd={ibMyT~H%Rw&)CC>U)>h6M2+5&d9UBKSpIEUR!O5yLUyQ?pSCYKvvY zy9=wVWPt0C)x^GWZFcOt_jDCs@7jzZSaKN$uns#0lA?$oezbaB_;R>}O5UWoT2W-A zcHLY*T1`D{Hw70wh_>2p{g}R@wUYWTuLHR>9g+plq9wN|Prm}gOqA0>bB)Z*u*a`t z5v>e|_G(NJ1qksXqnl>Mo^%Ou=GhBf(o5|0PI_RflVScl z8My4jSQBGnUKg5ocv0fu-Eb1&jyJSXMX2$+JC75yx7hUOTPEw5holf5t_9FCmUk75n`WG0ts zcb;%9v8ND~8pGW=m*B>W57pom==HHYKm1%Cts+VToP6#}I{XX7Q+5&}ZED!#@iZw? zNPH=topkyZGMu>QOIr;wU{E*YT;6#bvrHE~~pjOwV1S1N?$AsEg7Ftr+T0T2FoxyjB`G8e@};$Sp1#bYHiC!z zdR9@%lD-1H&RlPz0KMKSx6=+bpH7^}zCb?+Bd6Z${;fO4m{m|g099_h(R z*6gFQK;^S#Pkg4c=cC#fO2x(}aur`KbqqX{=K}3vMDESKjxp?vDJSruZ*8R@V^M zBjRsnX4o~HInsCUBD(i8zUF8<)wLsf>V5eUv8GpbduL2(kW9#P~%~%v6 z(hY4`b;0N`v$@XAWoJJ6UjE|-;Jc}~&^!}P_$*y)UrG@3y|3xba&KlIuP(HY%r^cN zsuHa%WZ1ZWuCXD)acrOI=gMQ4CZR6XIq}qTLE|9(H{fC#Rg`t65z@!1KyMP}q)h|; z7P*>#v6KDw&#qSG?=0n#*cNSPR#5>=C%s&No9PSwd9RWgz6o=+&v9u`Z|L>w))H^w zVx1$C!@P5At#2Qk;**h%P+Ul(llvCT3R)1`{pX0x*hE=r3$oGTuE5gTD&MNy)4|7= z&SXS#)tY4<7!b^##&WCu^rVa|g_nRyf!YK96UCey?Y`s)F8;aQTwiwfi2&=gxNcXXWug30LX3g*RvuCu4s885OcY9Qw@op1fiX$^tlYBsz! z4kyOKhKdA^nR%wuj_>Qo`QM-Z$sPR_dD<}sCxTgfyyd0rYwxbWkne{-N)Y;YwlWl7 zD-@bFfhKs7&73yR-w%cv@WLphN%G%WLJe**E_7i)dN}1;(N}KVOsnPyk0s0FtQRGT^6%|M3rk}3R6X$;Krlm3iSiXz z4zzT!|+{wtjrH&tu3a)&xPCYgEu zCPdd@hM?eXin?(0x{%_)-iy64(D6dUJZ_71@kaU~CcT*SC!M=KvhSI9Ah{3VaY;Dz zoltR8k?s})+#k+fgcn5qI`*tey56~Xui4xV&zUn&2g9}7kGBYo4_jy8)?UPN2`*QT z;mq_RXSyc@r;QMC7KVwKuz!M3YIoCb^haCFnJt1_Xm&@kvcxF6F|4-vqBjVZO7ezK z4QCk;9a+(}luH|M4@hC6$l_|cja}7WHMeq#7O7e7;-7+FpDSS4lf_J}E$0f&_9)fG z7^=4E+ErN7bvS+hvUa`q>NRa4pZS>^&*4K)HJioa+gZQgeA%t5TZstxXB8yOtOJ&T z-OTY89+u?F?uR7 zZbKCKTaud_L{2`SCqz8Ff!U5-!pAjO@xQB-#QM`m`479t_>v%dKN%aJ2Ebp(@P2&L zbQ=a=o>kAec!_EQuka6wpnBr%^LHm0HL=rhUz^=lb*6Yc84oDie({Q+`4`#G0!P7V zf4_Jmf#ZU^B{E8xdRQcIzKg;qBREGOnxaYes+?MI(-`aHj7ZI6`9@}If7 zL*L zcPAp=d#|nwt`q-BK_If==PN|_qk;?_a8ja@i!rlPYSIn zk8)CS_X3a&%)sBH;qt=hg?VU9wB0M`0jH#-i2?jZ*2=HT9xz}8j>1Wby$#nB-R4d< zl+E%;e)z?+N-v)vJgHTl8;^6RmBaw6dRwyiyeP}Nn`$q>W}TN^fI^{eStjlcI>;$) zwHHfjF~87QeCD%m6AJIry4>p66CuBZBc3l=Tkkv- z@B?II1)M~$lQ*y2oLXXZ_cuU!8B?QQ0rsjLEnF!^189Kzd)Y0j(Jw2QE^{%X0PpB? zM$_muAB{;S!O{dP*J)Z?9Sha*HQ}*|m8#+=x^L}dp5a&mLHPUEc70yI{(x2tvqkhL zR&X@S2R1XIi%fBd(Ac@WtiIyndowkMEy4NLy<&0lZFQOaV1q+xv z3{$P&F6wDgo2WOtHCU`s4?Ptht@*!N0NaDmw{)z8C@V)}&k5njGu=@m8}BwE%`^md zI-Ym8BhB9HgI>MwK6@pguDkE_GhN>4fY-M#e2$ea+<|G$d{Y$EVkD2ln*w_lN*Eao z&~b}aTOh5<02I;^C_*q~Q(om?fHTMXe+%|i5*XLK>Q$jRjr5`4Tn?otqV{-}C(A&& z)wmO1J0Kmn?DsjgQ2|5^!eG`4t^bYeN z53O0Q@5_hHCO0%sF&YT2g*q4ef{A&DZ)~4ERD?mrO_JBID*vSW3ylr8t?_X^nxy-S zIfaiz;3+(<9m(-^4zjDb)B|rVqLF~(ikZ^4|hQ$s-`rqtqtiEnBesL%s9xoe}$Vvv}9T($}Caba+kb^Jw2~i>%$k7$=^Q+#ivIM$EPk*>7)wF!S>C^9KI<>^uVzsACTP zLy2zfKi%1W7yKz9-RJqA6THJT)YCC21yVIJTw5?{hxP|26CvIqH!a zEk@5S2XH9@gVUs_8hQ!u!%tw!8>$o}M*GPiXZqow7aR{nQ7OLQdx`ev`Q*GqaRcl4 zci8Sj@NfKdniIA3f3GZjdb>{UcrcK}_Yg+W+i!=3tD2(MmeX(i@92zmG7;@yJVGna zw?|gdog1d1vhJu%+cJiNNWlEvwWE#uhu9d2=vyu3zgOpvskqg75-fbbtgfM+iu(B^ z)`PdS#SRXY*S7gWXknlGiV)xHa|VGxq7;5W~(P8-YBfW zLGx{SEoM5{)Be`VaS53;%7e!rc`cg=N*j+)(c@#PW^NBkYL7b@DpH#v1YvJ`rpu(h z{{#)zaAf|(<>_iSXpq7e&ZA3{riktSq5(;xHb=R+y6E397g!zAnbPjeG~Q>dxh&ro z9ZN|eL+DDZc*tj~} zc^k=w%orDWK$okIafVM>G<4bjj1^Jz0uY4y$?-;MCTj-jQ+`zTc=lRivn4EoZ|jls z^5*eJY%Nu8IMXu*An{(NQa!&ElOt$}0|aHmLX-+*L`}bpQ#l=&KWek$G0>tJRz0D| z3d745Q_p1vSP(-DGWILc!#QB_!dC|azl8u6Bm>sOyn5THnk`oMK3-K2BYW-AQ_Eemx(>z~vBnftas<%BnskUWOw=B5&S)@Jl@Um2TRP7xygcZ&Tw9b`H zDV&7VuT+%Q^}Gw{=bOK4e+=QKYP(+Rv;wF1S44wEsgIaV*Gnwm3c^%v@7eeYPdoho z>P(|qiJk|4&mn+$1p`F7anY|f(VRT-$K=!5Y#1RYOE(w|U;efnf+& zicF*W6p{;M+$7w~zODSv81))SK53mhi=x{UK~NF8Z@2l_bSQPSWCo969FJ6cvGjP# zo}`dLl$JIndWd_i@aXqp^1kIho0C{8jKf!+V<7+OZ&w|8;13^!-Rau>FsY{^l+9yqL($7;WX8it`ciQ(9e`@h?lQtl603iRR>yI z!L_Ot=r~E|xB+wovz&diN$~CrY}*wev@1PUiIml`A#K3Z>6p;{i1~EzW=)(`SY1ID z*p=v=Dcf7Enf1)*iM=A+Al#)Ffuhk#yY!)|X2eV7>Ww3G(01zSp9b9joX-+NaX5dA zT*5_oav_P+3=WTaAzGNc1Y=ac9|kZy8YV4np*xBnL2oPZwN(Ppvo##1*WXtB^MW~Q zdf!vtF$DWu9`I+0E2;CaO%^XkBv}NK=9xT_g>$ll$MBu#rvUR}3zI_2Ozp>$(yLeR z!5HQTcgzFeR#dT|*FdxtpTu8vamZH&ZMsr;SObj#5JxBOE(=h?suIcrT9>Fns#DvV2t`@w^${n;^L#P8Gy%IHXqqPO8)&d{HlGu+je7CN?coRGR z`1X{rz*9*1Phmdv7qs0E6nO{(6JsM5^!7nq%o@jSRu3!gF<#T|+rM7O*DuI?Jh>;A zDucd!0*J&()gE(04=6n=k-qfgpy|hI@eQ6{G?~WC`@5Nsd(M&YO zv0suKt;F>$v^Rf_EAKrPqEAX3Si-%7t{HDjt2?Lt&F%B|*d~3nPVz^Yn-WIpFHUlP zW7;Z)vuEW!u76UKbxn<_j&20xJ^~(3_<|#D@i*xxq#UU=!fvPeu5&co z1O>ep4L;5j-wZu7UpR};6gh;oR@(4aW9i3*2e4MG>h;~)WC|^X)7!I3Z75kce=N@U zk3!vvV&52(kD^HZ60X^#fpPRZqD zPTZCakkS7-%A}_!&z{kCP}wuv-}>64RNy3 zHQ^cu2bd=SfzeCu!&jNxrN zPH?(PvHC;3j6NNzXKA(^^HG3n04Hf?>n)mGN+VQ~j9J*cZ%#68sEtC3%;jXD-V=|W zc7TgPnC0!FM9j@BS%qai#F8AMh3AT0H+bVjxu0PMLT%=0fm(HU-PuE>-vVJ-sDc@U zJ@gX>4&nlQA#62U%!7g#hX(8e)8t5am~3FNz!hI3iO3D(hQ9d{ZR_ugH-LQ%DzZ%I z@2lJJf(8?7W&8?98AosJ+JQwmwka}h3R5^%vcYx&nJ{Ilde%l&Rr@S8L0H;{Ks%32 zv~s(*x}P&$oWzRPR)1nV3)V4np8Qq zFCzU?U{RA7=@!$wFfDleOvy_necxp!vR(a z_wRZ>Yptt(YtOu!x~Y?M^;njNiO!n$^R)-#n&0 zfy@uGFz~b7&gyHa5N@)uwImvoXiFg#m@9Wl;f~1&Jkzh%Y)-<%vh7d1W{U@sbs#m; zsDa%eocGDu)Yl24_I%M?*rKc=oc#&(;|$|`CMFxj<1c!Wy`h-#8YJ51AKvxwCNRyj zX18W|irhHhu|J!BpTAm7r`7pUt?u(c0QB+lv+g4;h>;o3b!*4hzC^Z=HLL*N_MLP& zN0VIffbl=a?H{Wpvy7aQ{+bI*2(amOf$v`O)5{kt>Wn&U)LK+kO*`0 z-EPa!B{UVgu)uskOEgbYQ24`W5h2X^iRq+s6ss=+jgyZ%f+~pYMiBV~NeHt`Hlfcn z697pLq^G>K_JmXpP4?BwA|+T^oY)!^hNa@YfnWxvn$dn#^qNgH!GD25Xc&lWP(K6$=R#=eoJ0BR0JLuY#LriZH-Uw)UJ87?;m_(XBh|Mzo$_e zq=aTlnPcQV!MI8Bt#22hvUpP#4)=e89V2j+5NveuTEaz@!cIcuOAl2H@f!2Yah zGGbmLCQ)jCqTOC@vkAHhs?(6Ts+36@g}19#;VCQ9b`<~HW*@f32q>?I@me@Qn$8MGH4b! za$b@G@f($8D33qnrlW#yQ32Hahu5UfB^*7d{@twh*ArdkK_HL{Ba~8DJ#q;W^D$*8 zrxGOt4)IA*fY38qrc}EtML*{HBV3Y$-b?@ug?|$k^5ejaVTV+6NGXeGenNr>q{%`L z<*F8WC0*DiTjFW$^5VwCugn%idO&-@g=mplrNNO6-BHrw?wD(6ZZ)yz0!XD8Ybv)S zV>bqkKppHJf?&ZfE2+L=EZbQWL<2`%%qW~xc9BI(lFfT@$GH0KgRa|dR=wF2TdOIVdqKcr^%6L$3g8E!Oe3%BxLf0$bCKHF3fh)W}!y@2w|4N&H1B=Us$nWm0M|4Yri#67?4!BPAH<|+E5)~)~wE6c1+q%INclZw|9U06hR0Rv1l*hskRGG+9st>fphT?Q;g zzdyqz@6B?B7tDFYL`dKH___)CDi9vG<#u)vS{$1e@P|AjX{KW?c30@O1L?5vJRFhy z=MMEJhzSc5Ox;or=d0k(1fr*o&ru3e2Lz!b+~Ivf9F3ZxcPnJ$?-F(er3z6C+q)4X z&%D1q5|RQPq9Qxa9{Kh`F{`Nirj4#|S+kW9vZGLR!--JK9R94E(iB>F2;zbr?|O8lYZFiH1_SdN56>Ne zYo5bzf9sO>Dg@D25r!q+*B*{y1lrz9%ommZ`izE}Io~S(Rs~9o>*$8R%$)5G;%o43 zv@#1P^L8HOk3IL9F!s*E)I$u%$vjamDI)n<-U#FC+=A#-yc5{U6=jlIEmBBqE8>|- zGCC;E+qye^LyfexnJ~H!Vg~8Z*SC;rY_y!H_1k#axSeN_ZPCEXE3qk$^!`C0OZO-3 zok}rXI6d*2rfpVdhkZ4sWdv_AtO*-d9n^C%d1s^JX^yGXZ43 zl%Vv|Z|S|T(>5ee`$BoItJvDJj<4+FhtMLQQl@U=dti|JLi9GVUQjd@%rzN z7Znxfy7}n;gh^eogf^J=Mq!wVd(Gz>Kfb=hThEvO9ZOHwHJCT*?iL<#$%cF@J$t^u zO+sQSe1j*tugF1&jf#P3Tv#Wo3gRvzsTKQj3SCP)+Qg!1R-ZV1_b5eAQj4NH%o`=Y zlXfgKP+cN>{2|w~7zu6T$PjqY5C6}Y`bA%gO#@Kl#3%hr@NMZ~+$3RazIxtHX-?u> zpBg_1U+a{U*Xqo>AlFFXX3OlM^jIx%Js}+qx`E?{? zWT(5*k~%zapKDBJnknIBd{v4ge})xh0uUbPP7^iZ_sTE3D9~E@oE)Nyse^q8PPDz8 zX@=fmzlkx0l1OD4mj>6EP2@|We{&w%`*i`Ha3(^rrE7UD!btXW(a;Ux+Oew4KOz37 zK5Sl9C(vrzps^HtVNZ@Z;i*N&U zI7d(O*92jq83M?M9YK6=eR4Hom`fEu%Xl%LW3EKg0I1OuFUk2p?YZ?#uKfB)U0Fw- z**8?-eihzTg}t$8`s|-Dk+bL(j<|VGp0xu_m{qUU0OdBvuWA;>s_`UuBH&pK{SR$K zxXnK)LJ%q?y&^5{wy+%N55jtRL=u=R;l_t&ieXGFXBW9@-DBpRUHpK%ZaTwoll68G z1Q3aOb>hA^>^wI8bf#IVoMX1DBGCN5PwM%z3g-Ia55FXL()~jT#j9-@swS}5RL<*b z!Iu2q9jl0;@J?9u6h+Xp3bktUo1=LAcwjU9o(PU3C0Vxr=3AH%;V^*db7=5g9+dr6 zA{F*-Q0mrTv*x8kjYyf zT!pqnBW-T^rUkI`ju@!YdRz*09BjSLN}Amj`VPL8vYhyqVSNc8wHt;VTATiAtUwv%{dl&oHhd(&th6HL7 zrTg`zppJ1M+H^yLUfxY@ z+2CE2B{&V0-CI*KZOKHJb}CN?EfFm76BA#T^iAuhbbSsq`|mDIo6;61rO2|C9-L<+ z1ElyTuq>n!!NNI0TuvHhEq;F!Q(VI@cgoY z38N=>*?MA1rQ|32lqw^}1#cA1fSA;^1t{Wk^u+_+PdGi)1`{+YgNg9MK$s3j{!UH& zFN^V+XG%XliJ$HL#7My9&@g3hB>wPVyK`h`A`!+b7F_ZRjP7JW^IH8!L;oXsXi&W{u!O^-_XJGRs%kiWR_ z8)vaMfD=F^eGzqAE4{8bC&M=d85a)cPL6I&lV(R;frt<|G=hFs7#WycUq&0GU&}oc zn){q8?PHqeEWQOEgs7`0mDm~jNIN+?S9zI}uxsrkbEKv!528SIrrT2EAcR5XeRzAd z_^@~kV*jPUUkKs9Jj3nyFqJ=b+Ap87uv3;uN-mxqjlKcE9M;D>lF?H8+v$SLYI#|1 zzZ zfSr6Jw3bG0$7K}OfKZdw>)EK1giGrQ@awWvhq6>lJA@p>4Nn6e7Yf?Iw;-TL(Bd-4 zK+a-kT*F^}%f+f2X&3MpWpGvhPp6gH=>8?DH~~qETg9Z%8h4sP!)nxupy&%3{Y*z3 zh$!d*jUM1WimY~f0GFZHq3fjDTWN~BnBF~+-k8d#wb5j<$HLhMWT}#PRk5r5Q4`f< z(Qnd!V`hGs?N&SyNZX*H$mA*q`;lYzkf(VOXJ)J%@}(uy)h1WA5DSPQVY2zAy%gI- z29l@QtUM(gJ7`GS)T(>3;JYJ(&9&6KNAl}%-TgR(Ij zI2!`B_$7@?4-6*~M{_ZJsR73)Aadr= z-%?onOt}4&0B7pSmlEGUbI_QH_)|B?!@ep!9LiHu8Ld~@qqb6`0t?4D@-^;>r?4 zn&!~Q6z&&%p|?;1*Z+lGNc820;fO{wG<;!W~G9sec@nky?9QXOfc&PM3{#{ho z+-H^ngOP_%{;J2yI7|Qq{Nw1WtonC=YcyvS;cKG}RpXZ;%9}s4HLyd!-=U)_12drE zmDqMIMgP1x8YlgWpQH58a{08t*68LltvQ#!)}=6{lxn$An?@IGfq1?=L<{e?X7g>m zZY7{WMfi^P*7jr=tr+Eb7oVapil-o!QT!pn*L=f;pgQf+v5Mcy=aM8duVADKN*L$a$+Ub(VrC|*ltRE?yPc#iiJt#?FP zcD_w#Pry;g!sNP~CGiFi$sZ!=(gKAijfoLgqF%2iipqF!8BMdU>Q8i|K)M|Y?7lYw zl);ZT%|=AWuvbvn5Mv$6|3${uAZAMLn0r$oaFu>Zoqx`G+RnlOcKR`;>&rg%A3i%m zq;QBN{I3Ei!g=tEtMos~U_mo1Jvd&<>TGiS+UAW1yXsCk1q0|k(FytKQqQ@YT#b}!hGm6AJEo1esX`Wj!<4|{*h z*oisRkF-L<`77NQ@DGpL8bmSUtrL_INN3N6=lFg6N7L`FE){4#^Z;sK`SoK25!C}t z&HQqD1HXeufpFWTHZSi#;xD1*g(JXQiy=}}3V`6e^ptkX8AzjU{oL`BWk`hf2D`yr zAUoiNjTN4uY4-0E{I+yY!##{Yu7STz@sEvSc-Pzc=11LJQ@2WMA&s%F*coo^ZrE+G z{P^?~9uuDbOtyFxt;_VB4_Si(h_*WqD|;V?4&8Hop4N{_8I?QAL`vApAW2%(H4?xh zQNB~zS=zHGEs9uMO8C%hn-U0M#Mv*QZTbDYM2|%roIqF%i{ynFLD|1o>o|?WKWOul z&4;k490pNe+lNuLDN@moL&wmXg;Nun*Iq9d!Na6nD_L3Cj3Hg$Ix(_TNOUXb|2y@i zfV!6hjW8A5g5c}#Z4(7$u3k14l@HovJ921YI5(VJID=@T7}Eew^iA=d-uc#}aB5WG zhp|MVUVD}bs|89L!)9j!{u7FDycw?@k7Oo5D+YsG`yDPEo++bRwWpkTN%J!OWoi2+ zoce{n2v+=1GhrKpRIW%wj^>52KKdfaM1{+!qpS*Ny3M;-sX15cA55r6VnhwaY7bsF z?mK?PgWK;Pml%_A*E!^l_)M(VqnpjMU|kb}WKd;9Vv(BbpTQ*Pk`invrazw&ZYG*r zHA_4BUv6PW_ni(U3cU$zQt}fupgpzzZl)WYEWyshv(%jERA{F)d(Aw56MAu*3j(vx zRFbvyiMlGB(ikPMB&?>U?NAdeh7Ds-g=+r^NKB$E(lGZ;p{!{6 z@Ah}&eW^hB4K762D+|f;A}un4iG;CH$|4UO*&Qp0j$)+*uwJtMnhC@ zNShojh39coTqmjmq}xpMzq{HfneqDwH;%smFPiwal0cn7Rr7W%fG=HO9mrjjmkort z3!K??&Aq|G=iJL6H3^^NyLVR3t;tn2CMz<*kgeYzd5=bARNC^@vLt(a4wFTM50&$J z6B?-)VPHJW1xb(kZS39JEhK@SJBNBN>#{mw*W5Sa@{zrJsvF8;`p-VfHKwA-?6CJZ~waEZn07AI$@54}Alz z!Hp=;yr_xxJs>NOBi32!b{`%>dBO&O{~{soHba0Hpck#qacE^CuKA_J#FZ<1+RUqr zvJAFs^pSsqzO|`s=sf!>05ot#Cx{)=lo)(#kU`}4Q#~zWDN%2%L`xRbF8gRWn?Oj& z?@g7qMN?89j56o5^2cs}G589_ncQF_Q8@FOETyc$0AN>o<&G01(&jkng2D#p#YZ)| zenCa8C9*Y#;ZuegpkVo@`!aF#R>DyLQ+^WRjtpDYZelk3W)jO8?;>Q8v z_oFY_hQDg_v+BRetjti>)T%<~{Pd)=qb0R-O&Trx`KWSt-;>bxUr=9YZzZVWOllLLfQ`y( z6>3)7^NCQm%nOSIDBv9vxf8qVyvDG$WYImdguk>QX+Ue+goLK2nDq+`{V#iy#V_=rugRBf5EOgH}*kG_VT%dA&Uq(#_t1a zRhkc&s_6E@t{{cDMtRuqGoup(g`Z$jYs+O;mm1oJ#%qDK%+78sJ|P6NBqOF3vxB{L z+>aB}CZpB^Iaa`zzt8ycN>}nTtHc^no5WE#iP}C3#row>otk6cC^|#xp4cqiz-${3 zE@n#{>i@ndpAkKnmw7gX0BI%gG?Kzu7^Yin% zFYhP)WV*KQsf^q{LPI?oDmuz_FKnX! E2LSsXng9R* literal 0 HcmV?d00001 diff --git a/gcc/rust/CONTRIBUTING.md b/gcc/rust/CONTRIBUTING.md new file mode 100644 index 00000000000..20e499c29e1 --- /dev/null +++ b/gcc/rust/CONTRIBUTING.md @@ -0,0 +1,130 @@ +## How to contribute to GCC Rust + +#### **Did you find a bug?** + +* **Ensure the bug was not already reported** by searching on GitHub under [Issues](https://github.com/Rust-GCC/gccrs/issues). + +* If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/Rust-GCC/gccrs/issues/new). + Be sure to include a **title and clear description**, as much relevant information as possible, and a **code sample** + or an **executable test case** demonstrating the expected behavior that is not occurring. + +#### **Do you want to submit a patch?** + +* Open a new GitHub pull request with the patch. + +* Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. + +* Before submitting, GCC development requires copyright assignment or the Developer's Certificate of Origin sign-off. + Please see the [Contributing to GCC](https://gcc.gnu.org/contribute.html) guide or [Developer's Certificate of Origin (DCO) Sign-off](https://gcc.gnu.org/dco.html) guide. + +* Patches sent to the [`gcc-rust` mailing list](https://gcc.gnu.org/mailman/listinfo/gcc-rust) are likewise welcome. +These will be imported into a GitHub PR to follow the normal review process, +and the link to the GitHub PR sent to the submitter. + +#### **Do you intend to add a new feature or change an existing one?** + +* Suggest your change in the [Zulip](https://gcc-rust.zulipchat.com/) and start writing code. + +* Do not open an issue on GitHub until you have collected positive feedback about the change. + GitHub issues are primarily intended for bug reports and fixes. + +#### **Do you have questions about the source code?** + +* Ask any question about how to use GCCRS in [Zulip](https://gcc-rust.zulipchat.com/). + +### **PR Policy** + +* The PR policy: Everything has to go through a PR + - An exception to this rule will be the merge commits of updating the repo against upstream GCC + +* Reviewers/Maintainers of the project (aka people who have bors rights) should be pinged for reviews/questions. + +* A PR can have one or several commits (split should have a technical/logical reason, ie. no fixup-ish commit) + +* Avoid PR's with merge commit unless there's a good reason + +* Where possible please add test cases to `gcc/testsuite/rust/` for all PRs. + Some issues may not be testable via dejagnu/automation such as debug dump changes. + +* Follow the [GCC coding style](https://gcc.gnu.org/codingconventions.html) (see `clang-format` below). + +* PRs won't be merged until the build and tests pass. + +* Please take the time to create good git commit messages. + See the existing format of them in the git log or refer to something like: https://chris.beams.io/posts/git-commit/ + +#### Running `clang-format` locally + +* on all files using python scripts +... corresponding to what the _Clang Format Lint_ (`.github/workflows/clang-format.yml`) +is doing, with `clang-format-10` being available locally, and avoiding the Docker overhead. + +```shell +$ wget 'https://github.com/DoozyX/clang-format-lint-action/raw/v0.11/run-clang-format.py' +$ cp contrib/clang-format .clang-format +$ python3 run-clang-format.py --clang-format-executable clang-format-10 --recursive --extensions h,cc gcc/rust/ +``` + +* on a given patch using python scripts +See the [clang-format documentation](https://clang.llvm.org/docs/ClangFormat.html#script-for-patch-reformatting) : + + $ git diff -U0 --no-color HEAD^ | clang-format-diff.py -i -p1 + +* using `git` interface + +At least on Debian and its derivative, each `clang-format` packages also comes +with `git-clang-format` command that can be used easily. It applies on staged +changes, and any modification can be seen as unstaged changes: + +```diff +$ git diff --cached +diff --git a/gcc/rust/rust-abi.h b/gcc/rust/rust-abi.h +index bd3043295ce..9559374ce60 100644 +--- a/gcc/rust/rust-abi.h ++++ b/gcc/rust/rust-abi.h +@@ -22,10 +22,10 @@ namespace Rust { + enum ABI + { + UNKNOWN, +- RUST, ++ RUST, + INTRINSIC, + C, +- CDECL, ++ CDECL, + STDCALL, + FASTCALL, + }; + +gccrs/gcc/rust on  dkm/clang_format [$!+?] +❯ git clang-format +changed files: + gcc/rust/rust-abi.h + +gccrs/gcc/rust on  dkm/clang_format [$!+?] +$ git diff rust-abi.h +diff --git a/gcc/rust/rust-abi.h b/gcc/rust/rust-abi.h +index 9559374ce60..bd3043295ce 100644 +--- a/gcc/rust/rust-abi.h ++++ b/gcc/rust/rust-abi.h +@@ -22,10 +22,10 @@ namespace Rust { + enum ABI + { + UNKNOWN, +- RUST, ++ RUST, + INTRINSIC, + C, +- CDECL, ++ CDECL, + STDCALL, + FASTCALL, + }; +``` + +Also note that you can use a given version of `clang-format` by using `git clang-format-10` if you have +installed that particular version. + +Thanks! :heart: :heart: :heart: + +GCCRS Team diff --git a/gcc/rust/README.md b/gcc/rust/README.md new file mode 100644 index 00000000000..fe38402f27a --- /dev/null +++ b/gcc/rust/README.md @@ -0,0 +1,264 @@ +![C/C++ CI](https://github.com/Rust-GCC/gccrs/workflows/C/C++%20CI/badge.svg) +[![GCC Bootstrap Build](https://github.com/Rust-GCC/gccrs/actions/workflows/bootstrap.yml/badge.svg)](https://github.com/Rust-GCC/gccrs/actions/workflows/bootstrap.yml) +[![Build Docker image](https://github.com/Rust-GCC/gccrs/actions/workflows/docker.yml/badge.svg)](https://github.com/Rust-GCC/gccrs/actions/workflows/docker.yml) +![Docker Pulls](https://img.shields.io/docker/pulls/philberty/gccrs) +[![project chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://gcc-rust.zulipchat.com/) +[![Bors enabled](https://bors.tech/images/badge_small.svg)](https://app.bors.tech/repositories/32890) +# GCC Rust +![GCC Rust](logo.png?raw=true "GCC rust Logo") + +Please note, the compiler is in a very early stage and not usable yet for compiling real Rust programs. + +gccrs is a full alternative implementation of the Rust language ontop of GCC with the goal +to become fully upstream with the GNU toolchain. + +The origin of this project was a community effort several years ago where Rust was still at version 0.9; +the language was subject to so much change that it became difficult for a community effort to play catch up. +Now that the language is stable, it is an excellent time to create alternative compilers. The developers of +the project are keen “Rustaceans” with a desire to give back to the Rust community and to learn what GCC is capable +of when it comes to a modern language. + +## Build Farm Status + +- [Debian i386](https://builder.sourceware.org/buildbot/#/builders/gccrust-debian-i386) [![Debian i386](https://builder.sourceware.org/buildbot/badges/gccrust-debian-i386.svg)](https://builder.sourceware.org/buildbot/#/builders/gccrust-debian-i386) +- [Debian ppc64](https://builder.sourceware.org/buildbot/#/builders/gccrust-debian-ppc64) [![Debian ppc64](https://builder.sourceware.org/buildbot/badges/gccrust-debian-ppc64.svg)](https://builder.sourceware.org/buildbot/#/builders/gccrust-debian-ppc64) +- [Debian testing-x86_64](https://builder.sourceware.org/buildbot/#/builders/146) [![Debian testing-x86_64](https://builder.sourceware.org/buildbot/badges/gccrust-debian-testing-x86_64.svg)](https://builder.sourceware.org/buildbot/#/builders/146) +- [Fedora arm64](https://builder.sourceware.org/buildbot/#/builders/179) [![Fedora arm64](https://builder.sourceware.org/buildbot/badges/gccrust-fedora-arm64.svg)](https://builder.sourceware.org/buildbot/#/builders/179) +- [Fedora ppc64le](https://builder.sourceware.org/buildbot/#/builders/gccrust-fedora-ppc64le) [![Fedora ppc64le](https://builder.sourceware.org/buildbot/badges/gccrust-fedora-ppc64le.svg)](https://builder.sourceware.org/buildbot/#/builders/gccrust-fedora-ppc64le) +- [Fedora s390x](https://builder.sourceware.org/buildbot/#/builders/gccrust-fedora-s390x) [![Fedora s390x](https://builder.sourceware.org/buildbot/badges/gccrust-fedora-s390x.svg)](https://builder.sourceware.org/buildbot/#/builders/gccrust-fedora-s390x) +- [Fedora X86_64](https://builder.sourceware.org/buildbot/#/builders/gccrust-fedora-x86_64) [![Fedora X86-64](https://builder.sourceware.org/buildbot/badges/gccrust-fedora-x86_64.svg)](https://builder.sourceware.org/buildbot/#/builders/gccrust-fedora-x86_64) +- [OpenSUSE Leap X86_64](https://builder.sourceware.org/buildbot/#/builders/104) [![OpenSUSE Leap X86_64](https://builder.sourceware.org/buildbot/badges/gccrust-opensuseleap-x86_64.svg)](https://builder.sourceware.org/buildbot/#/builders/104) +- [OpenSUSE tw X86_64](https://builder.sourceware.org/buildbot/#/builders/103) [![OpenSUSE tw X86_64](https://builder.sourceware.org/buildbot/badges/gccrust-opensusetw-x86_64.svg)](https://builder.sourceware.org/buildbot/#/builders/103) +- [Rawhide X86_64](https://builder.sourceware.org/buildbot/#/builders/132) [![Rawhide X86_64](https://builder.sourceware.org/buildbot/badges/gccrust-rawhide-x86_64.svg)](https://builder.sourceware.org/buildbot/#/builders/132) + +## FAQ + +Please find the answers to frequently asked questions over on: https://github.com/Rust-GCC/gccrs/wiki/Frequently-Asked-Questions + +## Development Environment + +### Building + +Fetch dependencies for Ubuntu: + +```bash +$ apt install build-essential libgmp3-dev libmpfr-dev libmpc-dev flex bison autogen gcc-multilib dejagnu +``` + +Clone the repository + +```bash +$ git clone https://github.com/Rust-GCC/gccrs +``` + +#### Linux + +It is important to remember that GNU toolchain projects are designed to be built outside of their source directory +which is why a build directory is created. + +```bash +$ mkdir gccrs-build +$ cd gccrs-build +$ ../gccrs/configure --prefix=$HOME/gccrs-install --disable-bootstrap --enable-multilib --enable-languages=rust +$ make +``` + +#### MacOS + +The path of header dir and sysroot should be specified when you configure the project. +```bash +$ mkdir mac-build +$ cd mac-build +$ ../gccrs/configure --prefix=$HOME/gccrs-install --disable-bootstrap --enable-multilib --enable-languages=rust --with-native-system-header-dir=/usr/include --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk +$ make + +``` + +#### Running GCC Rust + +Running the compiler itself without make install we can simply invoke the compiler proper: + +```bash +$ ./gcc/rust1 test.rs -frust-debug -frust-dump-parse -Warray-bounds -dumpbase test.rs -mtune=generic -march=x86-64 -O0 -version -fdump-tree-gimple -o test.s -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib64 +``` + +To invoke the compiler driver (gccrs) we need to: + +```bash +$ make install +``` + +Then invoke the compiler from the installation directory: + +```bash +$ $HOME/gccrs-install/gccrs -g -O2 -c test.rs -o test.o +$ $HOME/gccrs-install/gccrs -o test test.o +``` + +You can also setup your shell to automatically find the installed compiler. For example for `bash`, +add the following in your `$HOME/.bashrc`: + +```bash +export PATH=$HOME/gccrs-install/bin:$PATH + +``` + +## Testsuite + +Invoke the full testsuite from the build directory (`gccrs-build` in the previous commands): + +```bash +$ make check-rust +``` + +Invoke a subset of the testsuite. For example, to only run tests that are currently known/expected to fail: + +```bash +$ make check-rust RUNTESTFLAGS="xfail.exp" +``` +There are the following sets of tests: +- `compile.exp` : compilation tests +- `execute.exp` : execution tests +- `xfail.exp` : tests that are currently known/expected to fail + +Invoke only a specific test : + +```bash +$ make check-rust RUNTESTFLAGS="--all compile.exp=continue1.rs" +``` + +Logs (with corresponding commands) can be found in : `gccrs-build/gcc/testsuite/rust/rust.log`. + +See [GCC Testing documentation](https://gcc.gnu.org/install/test.html) for more details. + +Test cases are located within [`gcc/testsuite/rust/`](gcc/testsuite/rust/). +Please contribute your specific +test cases referencing any issues on Github. + +## Debugging + +### Enabling internal checks + +GCC has several internal checks that can be enabled during configuration. In the case of `gccrs`, +you can enable the following: +```bash +$ ../gccrs/configure --prefix=$HOME/gccrs-install --disable-bootstrap --enable-multilib --enable-languages=rust --enable-checking=gimple,tree,types +``` + +### GDB +You can directly invoke `gdb` on the `rust1` compiler process (you can find the +exact command adding `--verbose` to your `gccrs` invocation): +```bash +$ gccrs test.rs -O0 -S -o arithmetic_expressions1.s --verbose +... + /some/path/../../rust1 test.rs -quiet -dumpbase arithmetic_expressions1.rs -dumpbase-ext .rs + -mtune=generic -march=x86-64 -O0 -w -version -fdiagnostics-color=never -fno-diagnostics-show-caret -fno-diagnostics-show-line-numbers -fdiagnostics-urls=never -fdiagnostics-path-format=separate-events -o test.s -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu +... +$ gdb --args /some/path/../../rust1 test.rs -quiet -dumpbase arithmetic_expressions1.rs -dumpbase-ext .rs + -mtune=generic -march=x86-64 -O0 -w -version -fdiagnostics-color=never -fno-diagnostics-show-caret -fno-diagnostics-show-line-numbers -fdiagnostics-urls=never -fdiagnostics-path-format=separate-events -o test.s -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu +``` + +Or simply add the `-wrapper gdb,--args` option. +This will call each subcommand in `gdb` and you simply have to break/debug in `rust1`: +```bash +$ gccrs test.rs -O0 -S -o arithmetic_expressions1.s -wrapper gdb,--args +``` + +## Docker image + +There is a docker image hosted over on: + +https://hub.docker.com/repository/docker/philberty/gccrs + +```bash +$ docker pull philberty/gccrs +``` + +Or you can build your own image: + +```bash +$ docker build . -t gccrs-dev +``` +If you want to build an object file: + +```bash +$ docker run --rm -v "$PWD":/usr/src/myapp -w /usr/src/myapp \ + gccrs-dev:latest gccrs -g -O2 -c \ + gcc/testsuite/rust/compile/torture/type_infer1.rs -o type_infer1.o +``` + +If you want to build an executable file: +```bash +$ docker run --rm -v "$PWD":/usr/src/myapp -w /usr/src/myapp \ + gccrs-dev:latest gccrs -g -O2 \ + gcc/testsuite/rust/compile/torture/type_infer1.rs -o type_infer1 +``` + +To emit assembly : +```bash +$ docker run --rm -v "$PWD":/usr/src/myapp -w /usr/src/myapp \ + gccrs-dev:latest gccrs -g -O2 \ + gcc/testsuite/rust/compile/torture/type_infer1.rs -S -o type_infer1.s +``` + +To emit Rust front end debug output, you may add options like `-frust-debug`, `-frust-dump-all`. + + +## Contributing + +If you want to contribute to GCC Rust, you can find more information in [CONTRIBUTING.md](https://github.com/Rust-GCC/gccrs/blob/master/CONTRIBUTING.md). + +Please be aware this project is designed to be pushed upstream to GCC when we reach some milestones, +and this means we require copyright assignment or the Developer's Certificate of Origin sign-off. +Please see the [Contributing to GCC](https://gcc.gnu.org/contribute.html) guide or [Developer's Certificate of Origin (DCO) Sign-off](https://gcc.gnu.org/dco.html) guide. + +Not all contributions must be code; we would love to see new test cases or bugs and issues to be reported. +Feel free to add any comments on open PRs + + +## Continuous Integration + +When submitting (or updating) a [GitHub Pull Request](https://github.com/Rust-GCC/gccrs/pull/), +several automated checks are run. +Generally, a "green status" is necessary before merge. + + +### Compiler Diagnostics + +That is, here, diagnostics emitted by the "initial" compiler used to build GCC/Rust. + +If building a native toolchain, +GCC by default does a 3-stage bootstrap build (). +In addition to making sure that GCC is able to reproduce itself bit-by-bit, +this also means that stages 2+ are built with `-Werror` +(turning most _warning_ into _error_ diagnostics; see `--enable-werror`, +possibly enabled by default). +This helps to catch a good number of bugs, because it enforces that GCC compiles without compiler diagnostics; +it's a requirement for upstream patch submission (). + +GCC generally is only expected to be "warning-clean" without `--disable-bootstrap` +(that is, default `--enable-bootstrap` for a native build), +and not for the initial stage where it's using the "initial" compiler -- otherwise +we're at the mercy of whatever "initial" compiler we're using. +Doing a `--disable-bootstrap` build is much faster, of course, so we're often doing that: +for example, per the instructions above, or in the standard CI. +With that, we're missing out on the aspect that _enforces that GCC compiles without compiler diagnostics_. + +To encounter that, the default CI has a [_check for new warnings_ step](https://github.com/Rust-GCC/gccrs/pull/1026) +that verifies in the CI `--disable-bootstrap` build configuration that no new warnings are introduced. +If that step fails, it usually points out a new _warning_ you've introduced erroneously, and should address. +Occasionally it means that simply the `.github/bors_log_expected_warnings` file needs to be updated, +for example if due to any kind of "environmental changes" (for example, CI "initial" compiler changes). +Unless diligently reproducing the CI configuration (in particular "initial" compiler, GCC version), +it's not really feasible to reproduce this check locally. +If in doubt, do a local `--enable-bootstrap` build, or submit your changes, and wait for the CI system's results. + + +## Community + +We can be found on all usual Rust channels such as Zulip, but we also have our own channels: + +* GCC Rust Zulip: https://gcc-rust.zulipchat.com/ +* Twitter: https://twitter.com/gcc_rust +* GCC Mailing List: https://gcc.gnu.org/mailman/listinfo/gcc-rust +* irc: irc.oftc.net - gccrust diff --git a/gcc/rust/logo.png b/gcc/rust/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e5b22ad646f87e9ad00427f891d2f93baaf83520