]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fix rust breakage with nr2
authorPierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
Mon, 25 Nov 2024 17:04:06 +0000 (18:04 +0100)
committerP-E-P <32375388+P-E-P@users.noreply.github.com>
Tue, 21 Jan 2025 16:45:34 +0000 (16:45 +0000)
Nr2 did not emit the correct error message for break identifier "rust".

gcc/rust/ChangeLog:

* resolve/rust-late-name-resolver-2.0.cc (Late::visit): Add "rust"
identifier detection akin to nr1.
(funny_ice_finalizer): Copy ICE finalizer from nr1.
* resolve/rust-late-name-resolver-2.0.h: Add funny_error member
context state.
* Make-lang.in: Add new translation unit for new ice finalizer.
* resolve/rust-ast-resolve-expr.cc: Move ice
finalizer to it's own file.
* resolve/rust-ice-finalizer.cc: New file.
* resolve/rust-ice-finalizer.h: New file.

gcc/testsuite/ChangeLog:

* rust/compile/nr2/exclude: Remove break-rust3.rs from exclude list.

Signed-off-by: Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
gcc/rust/Make-lang.in
gcc/rust/resolve/rust-ast-resolve-expr.cc
gcc/rust/resolve/rust-ice-finalizer.cc [new file with mode: 0644]
gcc/rust/resolve/rust-ice-finalizer.h [new file with mode: 0644]
gcc/rust/resolve/rust-late-name-resolver-2.0.cc
gcc/rust/resolve/rust-late-name-resolver-2.0.h
gcc/testsuite/rust/compile/nr2/exclude

index 782c155fc32f3579908fc5efbbfbeb4d6b9c850a..751ae874def88b4fde506a651489783a34e3949c 100644 (file)
@@ -133,6 +133,7 @@ GRS_OBJS = \
     rust/rust-toplevel-name-resolver-2.0.o \
     rust/rust-early-name-resolver-2.0.o \
        rust/rust-finalize-imports-2.0.o \
+       rust/rust-ice-finalizer.o \
     rust/rust-late-name-resolver-2.0.o \
        rust/rust-immutable-name-resolution-context.o \
     rust/rust-early-name-resolver.o \
index 5936cf2c31ef6346cf192d66fd0f227f2cc75ae9..a7490156031058401f96f4a8e0bd1873561243f2 100644 (file)
@@ -22,8 +22,8 @@
 #include "rust-ast-resolve-type.h"
 #include "rust-ast-resolve-pattern.h"
 #include "rust-ast-resolve-path.h"
-#include "diagnostic.h"
 #include "rust-expr.h"
+#include "rust-ice-finalizer.h"
 
 namespace Rust {
 namespace Resolver {
@@ -108,45 +108,6 @@ ResolveExpr::visit (AST::AssignmentExpr &expr)
   ResolveExpr::go (expr.get_right_expr (), prefix, canonical_prefix);
 }
 
-/* The "break rust" Easter egg.
-
-   Backstory: once upon a time, there used to be a bug in rustc: it would ICE
-   during typechecking on a 'break' with an expression outside of a loop.  The
-   issue has been reported [0] and fixed [1], but in recognition of this, as a
-   special Easter egg, "break rust" was made to intentionally cause an ICE.
-
-   [0]: https://github.com/rust-lang/rust/issues/43162
-   [1]: https://github.com/rust-lang/rust/pull/43745
-
-   This was made in a way that does not break valid programs: namely, it only
-   happens when the 'break' is outside of a loop (so invalid anyway).
-
-   GCC Rust supports this essential feature as well, but in a slightly
-   different way.  Instead of delaying the error until type checking, we emit
-   it here in the resolution phase.  We, too, only do this to programs that
-   are already invalid: we only emit our funny ICE if the name "rust" (which
-   must be immediately inside a break-with-a-value expression) fails to
-   resolve.  Note that "break (rust)" does not trigger our ICE, only using
-   "break rust" directly does, and only if there's no "rust" in scope.  We do
-   this in the same way regardless of whether the "break" is outside of a loop
-   or inside one.
-
-   As a GNU extension, we also support "break gcc", much to the same effect,
-   subject to the same rules.  */
-
-/* The finalizer for our funny ICE.  This prints a custom message instead of
-   the default bug reporting instructions, as there is no bug to report.  */
-
-static void ATTRIBUTE_NORETURN
-funny_ice_finalizer (diagnostic_context *context,
-                    const diagnostic_info *diagnostic, diagnostic_t diag_kind)
-{
-  gcc_assert (diag_kind == DK_ICE_NOBT);
-  default_diagnostic_finalizer (context, diagnostic, diag_kind);
-  fnotice (stderr, "You have broken GCC Rust. This is a feature.\n");
-  exit (ICE_EXIT_CODE);
-}
-
 void
 ResolveExpr::visit (AST::IdentifierExpr &expr)
 {
diff --git a/gcc/rust/resolve/rust-ice-finalizer.cc b/gcc/rust/resolve/rust-ice-finalizer.cc
new file mode 100644 (file)
index 0000000..3ec8438
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ice-finalizer.h"
+
+namespace Rust {
+namespace Resolver {
+
+void ATTRIBUTE_NORETURN
+funny_ice_finalizer (diagnostic_context *context,
+                    const diagnostic_info *diagnostic, diagnostic_t diag_kind)
+{
+  gcc_assert (diag_kind == DK_ICE_NOBT);
+  default_diagnostic_finalizer (context, diagnostic, diag_kind);
+  fnotice (stderr, "You have broken GCC Rust. This is a feature.\n");
+  exit (ICE_EXIT_CODE);
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-ice-finalizer.h b/gcc/rust/resolve/rust-ice-finalizer.h
new file mode 100644 (file)
index 0000000..c73a729
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_ICE_FINALIZER_H
+#define RUST_ICE_FINALIZER_H
+
+#include "rust-linemap.h"
+#include "diagnostic.h"
+
+namespace Rust {
+namespace Resolver {
+
+/* The "break rust" Easter egg.
+
+   Backstory: once upon a time, there used to be a bug in rustc: it would ICE
+   during typechecking on a 'break' with an expression outside of a loop.  The
+   issue has been reported [0] and fixed [1], but in recognition of this, as a
+   special Easter egg, "break rust" was made to intentionally cause an ICE.
+
+   [0]: https://github.com/rust-lang/rust/issues/43162
+   [1]: https://github.com/rust-lang/rust/pull/43745
+
+   This was made in a way that does not break valid programs: namely, it only
+   happens when the 'break' is outside of a loop (so invalid anyway).
+
+   GCC Rust supports this essential feature as well, but in a slightly
+   different way.  Instead of delaying the error until type checking, we emit
+   it here in the resolution phase.  We, too, only do this to programs that
+   are already invalid: we only emit our funny ICE if the name "rust" (which
+   must be immediately inside a break-with-a-value expression) fails to
+   resolve.  Note that "break (rust)" does not trigger our ICE, only using
+   "break rust" directly does, and only if there's no "rust" in scope.  We do
+   this in the same way regardless of whether the "break" is outside of a loop
+   or inside one.
+
+   As a GNU extension, we also support "break gcc", much to the same effect,
+   subject to the same rules.  */
+
+/* The finalizer for our funny ICE.  This prints a custom message instead of
+   the default bug reporting instructions, as there is no bug to report.  */
+
+void ATTRIBUTE_NORETURN
+funny_ice_finalizer (diagnostic_context *context,
+                    const diagnostic_info *diagnostic, diagnostic_t diag_kind);
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif /* ! RUST_ICE_FINALIZER_H */
index f3ee08f4a03c295f2f1718215381ea4a06c9eab3..a7408fbe7b6adc69f58d38e1b41a7ace90e8c209 100644 (file)
@@ -27,6 +27,8 @@
 #include "rust-system.h"
 #include "rust-tyty.h"
 #include "rust-hir-type-check.h"
+#include "rust-ice-finalizer.h"
+#include "rust-ast.h"
 
 namespace Rust {
 namespace Resolver2_0 {
@@ -177,6 +179,34 @@ Late::visit (AST::SelfParam &param)
                                   param.get_node_id ());
 }
 
+void
+Late::visit (AST::BreakExpr &expr)
+{
+  if (expr.has_break_expr ())
+    {
+      auto &break_expr = expr.get_break_expr ();
+      if (break_expr.get_expr_kind () == AST::Expr::Kind::Identifier)
+       {
+         /* This is a break with an expression, and the expression is
+            just a single identifier.  See if the identifier is either
+            "rust" or "gcc", in which case we have "break rust" or "break
+            gcc", and so may need to emit our funny error.  We cannot yet
+            emit the error here though, because the identifier may still
+            be in scope, and ICE'ing on valid programs would not be very
+            funny.  */
+         std::string ident
+           = static_cast<AST::IdentifierExpr &> (expr.get_break_expr ())
+               .as_string ();
+         if (ident == "rust" || ident == "gcc")
+           funny_error = true;
+       }
+    }
+
+  DefaultResolver::visit (expr);
+
+  funny_error = false;
+}
+
 void
 Late::visit (AST::IdentifierExpr &expr)
 {
@@ -192,6 +222,13 @@ Late::visit (AST::IdentifierExpr &expr)
     {
       resolved = type;
     }
+  else if (funny_error)
+    {
+      diagnostic_finalizer (global_dc) = Resolver::funny_ice_finalizer;
+      emit_diagnostic (DK_ICE_NOBT, expr.get_locus (), -1,
+                      "are you trying to break %s? how dare you?",
+                      expr.as_string ().c_str ());
+    }
   else
     {
       rust_error_at (expr.get_locus (),
index 0efa69306065092902c172be611fa2d94fa8ccec..bdaae143e73d17b2f955b0ab39ed22e9832bacb1 100644 (file)
@@ -45,6 +45,7 @@ public:
 
   // resolutions
   void visit (AST::IdentifierExpr &) override;
+  void visit (AST::BreakExpr &) override;
   void visit (AST::PathInExpression &) override;
   void visit (AST::TypePath &) override;
   void visit (AST::Trait &) override;
@@ -58,6 +59,8 @@ public:
 private:
   /* Setup Rust's builtin types (u8, i32, !...) in the resolver */
   void setup_builtin_types ();
+
+  bool funny_error;
 };
 
 // TODO: Add missing mappings and data structures
index a8e3ba56e611c2c0fbe5d97f25c9d71e42ea3715..d53c14871731c4aaad0e3b8fddc84d5eac6f26ed 100644 (file)
@@ -1,6 +1,5 @@
 bounds1.rs
 break-rust2.rs
-break-rust3.rs
 canonical_paths1.rs
 cfg1.rs
 cfg3.rs