Skip to content

Commit

Permalink
Make ice finalizer common for both resolvers.
Browse files Browse the repository at this point in the history
gcc/rust/ChangeLog:

	* Make-lang.in:
	* resolve/rust-ast-resolve-expr.cc (funny_ice_finalizer):
	* resolve/rust-late-name-resolver-2.0.cc (funny_ice_finalizer):
	(Late::visit):
	* resolve/rust-ice-finalizer.cc: New file.
	* resolve/rust-ice-finalizer.h: New file.

Signed-off-by: Pierre-Emmanuel Patry <[email protected]>
  • Loading branch information
P-E-P committed Nov 25, 2024
1 parent be683fc commit cb1a29b
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 81 deletions.
1 change: 1 addition & 0 deletions gcc/rust/Make-lang.in
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
41 changes: 1 addition & 40 deletions gcc/rust/resolve/rust-ast-resolve-expr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
{
Expand Down
35 changes: 35 additions & 0 deletions gcc/rust/resolve/rust-ice-finalizer.cc
Original file line number Diff line number Diff line change
@@ -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
64 changes: 64 additions & 0 deletions gcc/rust/resolve/rust-ice-finalizer.h
Original file line number Diff line number Diff line change
@@ -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 */
43 changes: 2 additions & 41 deletions gcc/rust/resolve/rust-late-name-resolver-2.0.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#include "rust-system.h"
#include "rust-tyty.h"
#include "rust-hir-type-check.h"
#include "diagnostic.h"
#include "rust-ice-finalizer.h"

namespace Rust {
namespace Resolver2_0 {
Expand Down Expand Up @@ -206,45 +206,6 @@ Late::visit (AST::BreakExpr &expr)
funny_error = false;
}

/* 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
Late::visit (AST::IdentifierExpr &expr)
{
Expand All @@ -262,7 +223,7 @@ Late::visit (AST::IdentifierExpr &expr)
}
else if (funny_error)
{
diagnostic_finalizer (global_dc) = funny_ice_finalizer;
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 ());
Expand Down

0 comments on commit cb1a29b

Please sign in to comment.