Skip to content

Commit cb85611

Browse files
committed
Avoid stack overflowing when printing unevaluated const
Fixes rust-lang#68104 When printing the DefPath for an unevaluated const, we may end up trying to print the same const again. To avoid infinite recursion, we use the 'verbose' format when we try to re-entrantly print a const. This ensures that the pretty-printing process will always terminate.
1 parent 89988fe commit cb85611

File tree

3 files changed

+63
-18
lines changed

3 files changed

+63
-18
lines changed

src/librustc_middle/ty/print/pretty.rs

+40-18
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ thread_local! {
5454
static FORCE_IMPL_FILENAME_LINE: Cell<bool> = Cell::new(false);
5555
static SHOULD_PREFIX_WITH_CRATE: Cell<bool> = Cell::new(false);
5656
static NO_QUERIES: Cell<bool> = Cell::new(false);
57+
static NO_CONST_PATH: Cell<bool> = Cell::new(false);
5758
}
5859

5960
/// Avoids running any queries during any prints that occur
@@ -72,6 +73,15 @@ pub fn with_no_queries<F: FnOnce() -> R, R>(f: F) -> R {
7273
})
7374
}
7475

76+
pub fn with_no_const_path<F: FnOnce() -> R, R>(f: F) -> R {
77+
NO_CONST_PATH.with(|no_const_path| {
78+
let old = no_const_path.replace(true);
79+
let result = f();
80+
no_const_path.set(old);
81+
result
82+
})
83+
}
84+
7585
/// Force us to name impls with just the filename/line number. We
7686
/// normally try to use types. But at some points, notably while printing
7787
/// cycle errors, this can result in extra or suboptimal error output,
@@ -858,7 +868,9 @@ pub trait PrettyPrinter<'tcx>:
858868
) -> Result<Self::Const, Self::Error> {
859869
define_scoped_cx!(self);
860870

861-
if self.tcx().sess.verbose() {
871+
// See the call to `with_no_const_path` inside the
872+
// `ty::ConstKind::Unevaluated` for why we check `NO_CONST_PATH`
873+
if self.tcx().sess.verbose() || NO_CONST_PATH.with(|q| q.get()) {
862874
p!(write("Const({:?}: {:?})", ct.val, ct.ty));
863875
return Ok(self);
864876
}
@@ -882,29 +894,39 @@ pub trait PrettyPrinter<'tcx>:
882894

883895
match ct.val {
884896
ty::ConstKind::Unevaluated(did, substs, promoted) => {
885-
if let Some(promoted) = promoted {
886-
p!(print_value_path(did, substs));
887-
p!(write("::{:?}", promoted));
888-
} else {
889-
match self.tcx().def_kind(did) {
890-
DefKind::Static | DefKind::Const | DefKind::AssocConst => {
891-
p!(print_value_path(did, substs))
892-
}
893-
_ => {
894-
if did.is_local() {
895-
let span = self.tcx().def_span(did);
896-
if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span)
897-
{
898-
p!(write("{}", snip))
897+
// Don't re-entrantly enter this code path: that is,
898+
// don't try to print the DefPath of an unevaluated const
899+
// while we're already printing the DefPath of an unevaluated
900+
// const. This ensures that we never end up trying to recursively
901+
// print a const that we're already printing.
902+
// See issue #68104 for more details
903+
self = with_no_const_path(|| {
904+
if let Some(promoted) = promoted {
905+
p!(print_value_path(did, substs));
906+
p!(write("::{:?}", promoted));
907+
} else {
908+
match self.tcx().def_kind(did) {
909+
DefKind::Static | DefKind::Const | DefKind::AssocConst => {
910+
p!(print_value_path(did, substs))
911+
}
912+
_ => {
913+
if did.is_local() {
914+
let span = self.tcx().def_span(did);
915+
if let Ok(snip) =
916+
self.tcx().sess.source_map().span_to_snippet(span)
917+
{
918+
p!(write("{}", snip))
919+
} else {
920+
print_underscore!()
921+
}
899922
} else {
900923
print_underscore!()
901924
}
902-
} else {
903-
print_underscore!()
904925
}
905926
}
906927
}
907-
}
928+
Ok(self)
929+
})?;
908930
}
909931
ty::ConstKind::Infer(..) => print_underscore!(),
910932
ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#![feature(const_generics)]
2+
3+
pub struct Num<const N: usize>;
4+
5+
// Braces around const expression causes crash
6+
impl Num<{5}> {
7+
pub fn five(&self) {
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// aux-build:impl-const.rs
2+
// run-pass
3+
4+
#![feature(const_generics)]
5+
#![allow(incomplete_features)]
6+
7+
extern crate impl_const;
8+
9+
use impl_const::*;
10+
11+
pub fn main() {
12+
let n = Num::<5>;
13+
n.five();
14+
}

0 commit comments

Comments
 (0)