From: Pierre-Emmanuel Patry <pierre-emmanuel.pa...@embecosm.com>

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.pa...@embecosm.com>
---
 gcc/rust/Make-lang.in                         |  1 +
 gcc/rust/resolve/rust-ast-resolve-expr.cc     | 42 +-----------
 gcc/rust/resolve/rust-ice-finalizer.cc        | 36 ++++++++++
 gcc/rust/resolve/rust-ice-finalizer.h         | 65 +++++++++++++++++++
 .../resolve/rust-late-name-resolver-2.0.cc    | 37 +++++++++++
 .../resolve/rust-late-name-resolver-2.0.h     |  3 +
 gcc/testsuite/rust/compile/nr2/exclude        |  1 -
 7 files changed, 143 insertions(+), 42 deletions(-)
 create mode 100644 gcc/rust/resolve/rust-ice-finalizer.cc
 create mode 100644 gcc/rust/resolve/rust-ice-finalizer.h

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index b6f3a35e4e6..f317c678359 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -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 \
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc 
b/gcc/rust/resolve/rust-ast-resolve-expr.cc
index 6524376a011..9d5d00fa6a2 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc
@@ -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,46 +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_text_finalizer (diagnostic_text_output_format &text_output,
-                         const diagnostic_info *diagnostic,
-                         diagnostic_t diag_kind)
-{
-  gcc_assert (diag_kind == DK_ICE_NOBT);
-  default_diagnostic_text_finalizer (text_output, 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
index 00000000000..bd4763f8c76
--- /dev/null
+++ b/gcc/rust/resolve/rust-ice-finalizer.cc
@@ -0,0 +1,36 @@
+// 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_text_finalizer (diagnostic_text_output_format &text_output,
+                         const diagnostic_info *diagnostic,
+                         diagnostic_t diag_kind)
+{
+  gcc_assert (diag_kind == DK_ICE_NOBT);
+  default_diagnostic_text_finalizer (text_output, 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
index 00000000000..85ab88ff714
--- /dev/null
+++ b/gcc/rust/resolve/rust-ice-finalizer.h
@@ -0,0 +1,65 @@
+// 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_text_finalizer (diagnostic_text_output_format &text_output,
+                         const diagnostic_info *diagnostic,
+                         diagnostic_t diag_kind);
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif /* ! RUST_ICE_FINALIZER_H */
diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc 
b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
index 5aea6a43ed6..802f6a4d2ab 100644
--- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
@@ -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_text_finalizer (global_dc) = 
Resolver::funny_ice_text_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 (),
diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.h 
b/gcc/rust/resolve/rust-late-name-resolver-2.0.h
index ade78c5bc5f..95ad338417c 100644
--- a/gcc/rust/resolve/rust-late-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.h
@@ -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
diff --git a/gcc/testsuite/rust/compile/nr2/exclude 
b/gcc/testsuite/rust/compile/nr2/exclude
index a8e3ba56e61..d53c1487173 100644
--- a/gcc/testsuite/rust/compile/nr2/exclude
+++ b/gcc/testsuite/rust/compile/nr2/exclude
@@ -1,6 +1,5 @@
 bounds1.rs
 break-rust2.rs
-break-rust3.rs
 canonical_paths1.rs
 cfg1.rs
 cfg3.rs
-- 
2.45.2

Reply via email to