diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index a7f852a432c82..3f71a53f963e4 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -201,19 +201,19 @@ impl<'tcx> Context<'tcx> {
} else {
tyname.as_str()
};
- let page = layout::Page {
- css_class: tyname_s,
- root_path: &self.root_path(),
- static_root_path: self.shared.static_root_path.as_deref(),
- title: &title,
- description: &desc,
- keywords: &keywords,
- resource_suffix: &self.shared.resource_suffix,
- extra_scripts: &[],
- static_extra_scripts: &[],
- };
if !self.render_redirect_pages {
+ let page = layout::Page {
+ css_class: tyname_s,
+ root_path: &self.root_path(),
+ static_root_path: self.shared.static_root_path.as_deref(),
+ title: &title,
+ description: &desc,
+ keywords: &keywords,
+ resource_suffix: &self.shared.resource_suffix,
+ extra_scripts: &[],
+ static_extra_scripts: &[],
+ };
layout::render(
&self.shared.layout,
&page,
@@ -223,23 +223,31 @@ impl<'tcx> Context<'tcx> {
)
} else {
if let Some(&(ref names, ty)) = self.cache().paths.get(&it.def_id.expect_def_id()) {
- let mut path = String::new();
- for name in &names[..names.len() - 1] {
- path.push_str(&name.as_str());
- path.push('/');
- }
- path.push_str(&item_path(ty, &names.last().unwrap().as_str()));
- match self.shared.redirections {
- Some(ref redirections) => {
- let mut current_path = String::new();
- for name in &self.current {
- current_path.push_str(&name.as_str());
- current_path.push('/');
+ if self.current.len() + 1 != names.len()
+ || self.current.iter().zip(names.iter()).any(|(a, b)| a != b)
+ {
+ // We checked that the redirection isn't pointing to the current file,
+ // preventing an infinite redirection loop in the generated
+ // documentation.
+
+ let mut path = String::new();
+ for name in &names[..names.len() - 1] {
+ path.push_str(&name.as_str());
+ path.push('/');
+ }
+ path.push_str(&item_path(ty, &names.last().unwrap().as_str()));
+ match self.shared.redirections {
+ Some(ref redirections) => {
+ let mut current_path = String::new();
+ for name in &self.current {
+ current_path.push_str(&name.as_str());
+ current_path.push('/');
+ }
+ current_path.push_str(&item_path(ty, &names.last().unwrap().as_str()));
+ redirections.borrow_mut().insert(current_path, path);
}
- current_path.push_str(&item_path(ty, &names.last().unwrap().as_str()));
- redirections.borrow_mut().insert(current_path, path);
+ None => return layout::redirect(&format!("{}{}", self.root_path(), path)),
}
- None => return layout::redirect(&format!("{}{}", self.root_path(), path)),
}
}
String::new()
diff --git a/src/test/rustdoc/infinite-redirection.rs b/src/test/rustdoc/infinite-redirection.rs
new file mode 100644
index 0000000000000..96a43323ce29d
--- /dev/null
+++ b/src/test/rustdoc/infinite-redirection.rs
@@ -0,0 +1,29 @@
+#![crate_name = "foo"]
+
+// This test ensures that there is no "infinite redirection" file generated (a
+// file which redirects to itself).
+
+// We check it's not a redirection file.
+// @has 'foo/builders/struct.ActionRowBuilder.html'
+// @has - '//*[@id="synthetic-implementations"]' 'Auto Trait Implementations'
+
+// And that the link in the module is targetting it.
+// @has 'foo/builders/index.html'
+// @has - '//a[@href="struct.ActionRowBuilder.html"]' 'ActionRowBuilder'
+
+mod auto {
+ mod action_row {
+ pub struct ActionRowBuilder;
+ }
+
+ #[doc(hidden)]
+ pub mod builders {
+ pub use super::action_row::ActionRowBuilder;
+ }
+}
+
+pub use auto::*;
+
+pub mod builders {
+ pub use crate::auto::builders::*;
+}