Auto merge of #83905 - JohnTitor:rollup-pa1la80, r=JohnTitor
Rollup of 8 pull requests Successful merges: - #83370 (Add `x.py setup tools` which enables `download-rustc` by default) - #83489 (Properly suggest deref in else block) - #83734 (Catch a bad placeholder type error for statics in `extern`s) - #83814 (expand: Do not ICE when a legacy AST-based macro attribute produces and empty expression) - #83835 (rustdoc: sort search index items for compression) - #83849 (rustdoc: Cleanup handling of associated items for intra-doc links) - #83881 (⬆️ rust-analyzer) - #83885 (Document compiler/ with -Aprivate-intra-doc-links) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
8e6b478a5a
25 changed files with 367 additions and 192 deletions
|
@ -45,9 +45,6 @@ macro_rules! forward {
|
|||
pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)?) -> &Self
|
||||
) => {
|
||||
$(#[$attrs])*
|
||||
// we always document with --document-private-items
|
||||
#[cfg_attr(not(bootstrap), allow(rustdoc::private_intra_doc_links))]
|
||||
#[cfg_attr(bootstrap, allow(private_intra_doc_links))]
|
||||
#[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")]
|
||||
pub fn $n(&self, $($name: $ty),*) -> &Self {
|
||||
self.diagnostic.$n($($name),*);
|
||||
|
@ -62,9 +59,6 @@ macro_rules! forward {
|
|||
) => {
|
||||
$(#[$attrs])*
|
||||
#[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")]
|
||||
// we always document with --document-private-items
|
||||
#[cfg_attr(not(bootstrap), allow(rustdoc::private_intra_doc_links))]
|
||||
#[cfg_attr(bootstrap, allow(private_intra_doc_links))]
|
||||
pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
|
||||
self.0.diagnostic.$n($($name),*);
|
||||
self
|
||||
|
@ -82,9 +76,6 @@ macro_rules! forward {
|
|||
) => {
|
||||
$(#[$attrs])*
|
||||
#[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")]
|
||||
// we always document with --document-private-items
|
||||
#[cfg_attr(not(bootstrap), allow(rustdoc::private_intra_doc_links))]
|
||||
#[cfg_attr(bootstrap, allow(private_intra_doc_links))]
|
||||
pub fn $n<$($generic: $bound),*>(&mut self, $($name: $ty),*) -> &mut Self {
|
||||
self.0.diagnostic.$n($($name),*);
|
||||
self
|
||||
|
|
|
@ -735,7 +735,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
});
|
||||
}
|
||||
};
|
||||
fragment_kind.expect_from_annotatables(items)
|
||||
if fragment_kind == AstFragmentKind::Expr && items.is_empty() {
|
||||
let msg =
|
||||
"removing an expression is not supported in this position";
|
||||
self.cx.span_err(span, msg);
|
||||
fragment_kind.dummy(span)
|
||||
} else {
|
||||
fragment_kind.expect_from_annotatables(items)
|
||||
}
|
||||
}
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#![feature(nll)]
|
||||
#![cfg_attr(bootstrap, feature(or_patterns))]
|
||||
#![recursion_limit = "256"]
|
||||
#![allow(rustdoc::private_intra_doc_links)]
|
||||
|
||||
pub use rustc_hir::def::{Namespace, PerNS};
|
||||
|
||||
|
|
|
@ -366,6 +366,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
false
|
||||
}
|
||||
|
||||
/// If the given `HirId` corresponds to a block with a trailing expression, return that expression
|
||||
crate fn maybe_get_block_expr(&self, hir_id: hir::HirId) -> Option<&'tcx hir::Expr<'tcx>> {
|
||||
match self.tcx.hir().find(hir_id)? {
|
||||
Node::Expr(hir::Expr { kind: hir::ExprKind::Block(block, ..), .. }) => block.expr,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the given expression is an `else if`.
|
||||
crate fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool {
|
||||
if let hir::ExprKind::If(..) = expr.kind {
|
||||
let parent_id = self.tcx.hir().get_parent_node(expr.hir_id);
|
||||
if let Some(Node::Expr(hir::Expr {
|
||||
kind: hir::ExprKind::If(_, _, Some(else_expr)),
|
||||
..
|
||||
})) = self.tcx.hir().find(parent_id)
|
||||
{
|
||||
return else_expr.hir_id == expr.hir_id;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// This function is used to determine potential "simple" improvements or users' errors and
|
||||
/// provide them useful help. For example:
|
||||
///
|
||||
|
@ -652,6 +675,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
};
|
||||
let suggestion = if is_struct_pat_shorthand_field {
|
||||
format!("{}: *{}", code, code)
|
||||
} else if self.is_else_if_block(expr) {
|
||||
// Don't suggest nonsense like `else *if`
|
||||
return None;
|
||||
} else if let Some(expr) = self.maybe_get_block_expr(expr.hir_id) {
|
||||
format!("*{}", sm.span_to_snippet(expr.span).unwrap_or(code))
|
||||
} else {
|
||||
format!("*{}", code)
|
||||
};
|
||||
|
|
|
@ -734,8 +734,14 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
|||
tcx.ensure().generics_of(item.def_id);
|
||||
tcx.ensure().type_of(item.def_id);
|
||||
tcx.ensure().predicates_of(item.def_id);
|
||||
if let hir::ForeignItemKind::Fn(..) = item.kind {
|
||||
tcx.ensure().fn_sig(item.def_id);
|
||||
match item.kind {
|
||||
hir::ForeignItemKind::Fn(..) => tcx.ensure().fn_sig(item.def_id),
|
||||
hir::ForeignItemKind::Static(..) => {
|
||||
let mut visitor = PlaceholderHirTyCollector::default();
|
||||
visitor.visit_foreign_item(item);
|
||||
placeholder_type_error(tcx, None, &[], visitor.0, false, None);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,5 @@ debug-logging = true
|
|||
incremental = true
|
||||
|
||||
[llvm]
|
||||
# Will download LLVM from CI if available on your platform (Linux only for now)
|
||||
# https://github.com/rust-lang/rust/issues/77084 tracks support for more platforms
|
||||
# Will download LLVM from CI if available on your platform.
|
||||
download-ci-llvm = "if-available"
|
||||
|
|
16
src/bootstrap/defaults/config.tools.toml
Normal file
16
src/bootstrap/defaults/config.tools.toml
Normal file
|
@ -0,0 +1,16 @@
|
|||
# These defaults are meant for contributors to tools which build on the
|
||||
# compiler, but do not modify it directly.
|
||||
[rust]
|
||||
# This enables `RUSTC_LOG=debug`, avoiding confusing situations
|
||||
# where adding `debug!()` appears to do nothing.
|
||||
# However, it makes running the compiler slightly slower.
|
||||
debug-logging = true
|
||||
# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
|
||||
incremental = true
|
||||
# Download rustc from CI instead of building it from source.
|
||||
# This cuts compile times by almost 60x, but means you can't modify the compiler.
|
||||
download-rustc = "if-unchanged"
|
||||
|
||||
[llvm]
|
||||
# Will download LLVM from CI if available on your platform.
|
||||
download-ci-llvm = "if-available"
|
|
@ -549,6 +549,8 @@ impl Step for Rustc {
|
|||
// Build cargo command.
|
||||
let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "doc");
|
||||
cargo.rustdocflag("--document-private-items");
|
||||
// Since we always pass --document-private-items, there's no need to warn about linking to private items.
|
||||
cargo.rustdocflag("-Arustdoc::private-intra-doc-links");
|
||||
cargo.rustdocflag("--enable-index-page");
|
||||
cargo.rustdocflag("-Zunstable-options");
|
||||
cargo.rustdocflag("-Znormalize-docs");
|
||||
|
|
|
@ -13,6 +13,7 @@ pub enum Profile {
|
|||
Compiler,
|
||||
Codegen,
|
||||
Library,
|
||||
Tools,
|
||||
User,
|
||||
}
|
||||
|
||||
|
@ -24,15 +25,16 @@ impl Profile {
|
|||
pub fn all() -> impl Iterator<Item = Self> {
|
||||
use Profile::*;
|
||||
// N.B. these are ordered by how they are displayed, not alphabetically
|
||||
[Library, Compiler, Codegen, User].iter().copied()
|
||||
[Library, Compiler, Codegen, Tools, User].iter().copied()
|
||||
}
|
||||
|
||||
pub fn purpose(&self) -> String {
|
||||
use Profile::*;
|
||||
match self {
|
||||
Library => "Contribute to the standard library",
|
||||
Compiler => "Contribute to the compiler or rustdoc",
|
||||
Compiler => "Contribute to the compiler itself",
|
||||
Codegen => "Contribute to the compiler, and also modify LLVM or codegen",
|
||||
Tools => "Contribute to tools which depend on the compiler, but do not modify it directly (e.g. rustdoc, clippy, miri)",
|
||||
User => "Install Rust from source",
|
||||
}
|
||||
.to_string()
|
||||
|
@ -53,9 +55,12 @@ impl FromStr for Profile {
|
|||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"lib" | "library" => Ok(Profile::Library),
|
||||
"compiler" | "rustdoc" => Ok(Profile::Compiler),
|
||||
"compiler" => Ok(Profile::Compiler),
|
||||
"llvm" | "codegen" => Ok(Profile::Codegen),
|
||||
"maintainer" | "user" => Ok(Profile::User),
|
||||
"tools" | "tool" | "rustdoc" | "clippy" | "miri" | "rustfmt" | "rls" => {
|
||||
Ok(Profile::Tools)
|
||||
}
|
||||
_ => Err(format!("unknown profile: '{}'", s)),
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +73,7 @@ impl fmt::Display for Profile {
|
|||
Profile::Codegen => write!(f, "codegen"),
|
||||
Profile::Library => write!(f, "library"),
|
||||
Profile::User => write!(f, "user"),
|
||||
Profile::Tools => write!(f, "tools"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -103,6 +109,14 @@ pub fn setup(src_path: &Path, profile: Profile) {
|
|||
|
||||
let suggestions = match profile {
|
||||
Profile::Codegen | Profile::Compiler => &["check", "build", "test"][..],
|
||||
Profile::Tools => &[
|
||||
"check",
|
||||
"build",
|
||||
"test src/test/rustdoc*",
|
||||
"test src/tools/clippy",
|
||||
"test src/tools/miri",
|
||||
"test src/tools/rustfmt",
|
||||
],
|
||||
Profile::Library => &["check", "build", "test library/std", "doc"],
|
||||
Profile::User => &["dist", "build"],
|
||||
};
|
||||
|
|
|
@ -914,7 +914,7 @@ impl Attributes {
|
|||
.collect()
|
||||
}
|
||||
|
||||
crate fn get_doc_aliases(&self) -> FxHashSet<String> {
|
||||
crate fn get_doc_aliases(&self) -> Box<[String]> {
|
||||
let mut aliases = FxHashSet::default();
|
||||
|
||||
for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) {
|
||||
|
@ -931,7 +931,7 @@ impl Attributes {
|
|||
aliases.insert(attr.value_str().map(|s| s.to_string()).unwrap());
|
||||
}
|
||||
}
|
||||
aliases
|
||||
aliases.into_iter().collect::<Vec<String>>().into()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -120,10 +120,6 @@ crate struct Cache {
|
|||
// when gathering trait documentation on a type, hold impls here while
|
||||
// folding and add them to the cache later on if we find the trait.
|
||||
orphan_trait_impls: Vec<(DefId, FxHashSet<DefId>, Impl)>,
|
||||
|
||||
/// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
|
||||
/// we need the alias element to have an array of items.
|
||||
crate aliases: BTreeMap<String, Vec<usize>>,
|
||||
}
|
||||
|
||||
/// This struct is used to wrap the `cache` and `tcx` in order to run `DocFolder`.
|
||||
|
@ -309,15 +305,8 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
|
|||
parent,
|
||||
parent_idx: None,
|
||||
search_type: get_index_search_type(&item, &self.empty_cache, self.tcx),
|
||||
aliases: item.attrs.get_doc_aliases(),
|
||||
});
|
||||
|
||||
for alias in item.attrs.get_doc_aliases() {
|
||||
self.cache
|
||||
.aliases
|
||||
.entry(alias.to_lowercase())
|
||||
.or_insert(Vec::new())
|
||||
.push(self.cache.search_index.len() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
(Some(parent), None) if is_inherent_impl_item => {
|
||||
|
|
|
@ -82,18 +82,31 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
|
|||
parent: Some(did),
|
||||
parent_idx: None,
|
||||
search_type: get_index_search_type(&item, cache, tcx),
|
||||
aliases: item.attrs.get_doc_aliases(),
|
||||
});
|
||||
for alias in item.attrs.get_doc_aliases() {
|
||||
cache
|
||||
.aliases
|
||||
.entry(alias.to_lowercase())
|
||||
.or_insert(Vec::new())
|
||||
.push(cache.search_index.len() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let Cache { ref mut search_index, ref paths, ref mut aliases, .. } = *cache;
|
||||
let Cache { ref mut search_index, ref paths, .. } = *cache;
|
||||
|
||||
// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
|
||||
// we need the alias element to have an array of items.
|
||||
let mut aliases: BTreeMap<String, Vec<usize>> = BTreeMap::new();
|
||||
|
||||
// Sort search index items. This improves the compressibility of the search index.
|
||||
search_index.sort_unstable_by(|k1, k2| {
|
||||
// `sort_unstable_by_key` produces lifetime errors
|
||||
let k1 = (&k1.path, &k1.name, &k1.ty, &k1.parent);
|
||||
let k2 = (&k2.path, &k2.name, &k2.ty, &k2.parent);
|
||||
std::cmp::Ord::cmp(&k1, &k2)
|
||||
});
|
||||
|
||||
// Set up alias indexes.
|
||||
for (i, item) in search_index.iter().enumerate() {
|
||||
for alias in &item.aliases[..] {
|
||||
aliases.entry(alias.to_lowercase()).or_insert(Vec::new()).push(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Reduce `DefId` in paths into smaller sequential numbers,
|
||||
// and prune the paths that do not appear in the index.
|
||||
|
@ -201,7 +214,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
|
|||
doc: crate_doc,
|
||||
items: crate_items,
|
||||
paths: crate_paths,
|
||||
aliases,
|
||||
aliases: &aliases,
|
||||
})
|
||||
.expect("failed serde conversion")
|
||||
// All these `replace` calls are because we have to go through JS string for JSON content.
|
||||
|
|
|
@ -164,6 +164,7 @@ crate struct IndexItem {
|
|||
crate parent: Option<DefId>,
|
||||
crate parent_idx: Option<usize>,
|
||||
crate search_type: Option<IndexItemFunctionType>,
|
||||
crate aliases: Box<[String]>,
|
||||
}
|
||||
|
||||
/// A type used for the search index.
|
||||
|
|
|
@ -368,55 +368,28 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||
}
|
||||
|
||||
/// Given a primitive type, try to resolve an associated item.
|
||||
///
|
||||
/// HACK(jynelson): `item_str` is passed in instead of derived from `item_name` so the
|
||||
/// lifetimes on `&'path` will work.
|
||||
fn resolve_primitive_associated_item(
|
||||
&self,
|
||||
prim_ty: PrimitiveType,
|
||||
ns: Namespace,
|
||||
module_id: DefId,
|
||||
item_name: Symbol,
|
||||
item_str: &'path str,
|
||||
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
|
||||
) -> Option<(Res, String, Option<(DefKind, DefId)>)> {
|
||||
let tcx = self.cx.tcx;
|
||||
|
||||
prim_ty
|
||||
.impls(tcx)
|
||||
.into_iter()
|
||||
.find_map(|&impl_| {
|
||||
tcx.associated_items(impl_)
|
||||
.find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_)
|
||||
.map(|item| {
|
||||
let kind = item.kind;
|
||||
self.kind_side_channel.set(Some((kind.as_def_kind(), item.def_id)));
|
||||
match kind {
|
||||
ty::AssocKind::Fn => "method",
|
||||
ty::AssocKind::Const => "associatedconstant",
|
||||
ty::AssocKind::Type => "associatedtype",
|
||||
}
|
||||
})
|
||||
.map(|out| {
|
||||
(
|
||||
Res::Primitive(prim_ty),
|
||||
Some(format!("{}#{}.{}", prim_ty.as_str(), out, item_str)),
|
||||
)
|
||||
})
|
||||
})
|
||||
.ok_or_else(|| {
|
||||
debug!(
|
||||
"returning primitive error for {}::{} in {} namespace",
|
||||
prim_ty.as_str(),
|
||||
item_name,
|
||||
ns.descr()
|
||||
);
|
||||
ResolutionFailure::NotResolved {
|
||||
module_id,
|
||||
partial_res: Some(Res::Primitive(prim_ty)),
|
||||
unresolved: item_str.into(),
|
||||
}
|
||||
.into()
|
||||
})
|
||||
prim_ty.impls(tcx).into_iter().find_map(|&impl_| {
|
||||
tcx.associated_items(impl_)
|
||||
.find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_)
|
||||
.map(|item| {
|
||||
let kind = item.kind;
|
||||
let out = match kind {
|
||||
ty::AssocKind::Fn => "method",
|
||||
ty::AssocKind::Const => "associatedconstant",
|
||||
ty::AssocKind::Type => "associatedtype",
|
||||
};
|
||||
let fragment = format!("{}#{}.{}", prim_ty.as_str(), out, item_name);
|
||||
(Res::Primitive(prim_ty), fragment, Some((kind.as_def_kind(), item.def_id)))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/// Resolves a string as a macro.
|
||||
|
@ -490,8 +463,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||
module_id: DefId,
|
||||
extra_fragment: &Option<String>,
|
||||
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
|
||||
let tcx = self.cx.tcx;
|
||||
|
||||
if let Some(res) = self.resolve_path(path_str, ns, module_id) {
|
||||
match res {
|
||||
// FIXME(#76467): make this fallthrough to lookup the associated
|
||||
|
@ -534,29 +505,58 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||
}
|
||||
})?;
|
||||
|
||||
// FIXME: are these both necessary?
|
||||
let ty_res = if let Some(ty_res) = resolve_primitive(&path_root, TypeNS)
|
||||
// FIXME(#83862): this arbitrarily gives precedence to primitives over modules to support
|
||||
// links to primitives when `#[doc(primitive)]` is present. It should give an ambiguity
|
||||
// error instead and special case *only* modules with `#[doc(primitive)]`, not all
|
||||
// primitives.
|
||||
resolve_primitive(&path_root, TypeNS)
|
||||
.or_else(|| self.resolve_path(&path_root, TypeNS, module_id))
|
||||
{
|
||||
ty_res
|
||||
} else {
|
||||
// FIXME: this is duplicated on the end of this function.
|
||||
return if ns == Namespace::ValueNS {
|
||||
self.variant_field(path_str, module_id)
|
||||
} else {
|
||||
Err(ResolutionFailure::NotResolved {
|
||||
module_id,
|
||||
partial_res: None,
|
||||
unresolved: path_root.into(),
|
||||
.and_then(|ty_res| {
|
||||
let (res, fragment, side_channel) =
|
||||
self.resolve_associated_item(ty_res, item_name, ns, module_id)?;
|
||||
let result = if extra_fragment.is_some() {
|
||||
let diag_res = side_channel.map_or(res, |(k, r)| Res::Def(k, r));
|
||||
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(diag_res)))
|
||||
} else {
|
||||
// HACK(jynelson): `clean` expects the type, not the associated item
|
||||
// but the disambiguator logic expects the associated item.
|
||||
// Store the kind in a side channel so that only the disambiguator logic looks at it.
|
||||
if let Some((kind, id)) = side_channel {
|
||||
self.kind_side_channel.set(Some((kind, id)));
|
||||
}
|
||||
Ok((res, Some(fragment)))
|
||||
};
|
||||
Some(result)
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
if ns == Namespace::ValueNS {
|
||||
self.variant_field(path_str, module_id)
|
||||
} else {
|
||||
Err(ResolutionFailure::NotResolved {
|
||||
module_id,
|
||||
partial_res: None,
|
||||
unresolved: path_root.into(),
|
||||
}
|
||||
.into())
|
||||
}
|
||||
.into())
|
||||
};
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
let res = match ty_res {
|
||||
Res::Primitive(prim) => Some(
|
||||
self.resolve_primitive_associated_item(prim, ns, module_id, item_name, item_str),
|
||||
),
|
||||
/// Returns:
|
||||
/// - None if no associated item was found
|
||||
/// - Some((_, _, Some(_))) if an item was found and should go through a side channel
|
||||
/// - Some((_, _, None)) otherwise
|
||||
fn resolve_associated_item(
|
||||
&mut self,
|
||||
root_res: Res,
|
||||
item_name: Symbol,
|
||||
ns: Namespace,
|
||||
module_id: DefId,
|
||||
) -> Option<(Res, String, Option<(DefKind, DefId)>)> {
|
||||
let tcx = self.cx.tcx;
|
||||
|
||||
match root_res {
|
||||
Res::Primitive(prim) => self.resolve_primitive_associated_item(prim, ns, item_name),
|
||||
Res::Def(
|
||||
DefKind::Struct
|
||||
| DefKind::Union
|
||||
|
@ -599,59 +599,42 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||
ty::AssocKind::Const => "associatedconstant",
|
||||
ty::AssocKind::Type => "associatedtype",
|
||||
};
|
||||
Some(if extra_fragment.is_some() {
|
||||
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res)))
|
||||
} else {
|
||||
// HACK(jynelson): `clean` expects the type, not the associated item
|
||||
// but the disambiguator logic expects the associated item.
|
||||
// Store the kind in a side channel so that only the disambiguator logic looks at it.
|
||||
self.kind_side_channel.set(Some((kind.as_def_kind(), id)));
|
||||
Ok((ty_res, Some(format!("{}.{}", out, item_str))))
|
||||
})
|
||||
} else if ns == Namespace::ValueNS {
|
||||
debug!("looking for variants or fields named {} for {:?}", item_name, did);
|
||||
// FIXME(jynelson): why is this different from
|
||||
// `variant_field`?
|
||||
match tcx.type_of(did).kind() {
|
||||
ty::Adt(def, _) => {
|
||||
let field = if def.is_enum() {
|
||||
def.all_fields().find(|item| item.ident.name == item_name)
|
||||
} else {
|
||||
def.non_enum_variant()
|
||||
.fields
|
||||
.iter()
|
||||
.find(|item| item.ident.name == item_name)
|
||||
};
|
||||
field.map(|item| {
|
||||
if extra_fragment.is_some() {
|
||||
let res = Res::Def(
|
||||
if def.is_enum() {
|
||||
DefKind::Variant
|
||||
} else {
|
||||
DefKind::Field
|
||||
},
|
||||
item.did,
|
||||
);
|
||||
Err(ErrorKind::AnchorFailure(
|
||||
AnchorFailure::RustdocAnchorConflict(res),
|
||||
))
|
||||
} else {
|
||||
Ok((
|
||||
ty_res,
|
||||
Some(format!(
|
||||
"{}.{}",
|
||||
if def.is_enum() { "variant" } else { "structfield" },
|
||||
item.ident
|
||||
)),
|
||||
))
|
||||
}
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
// HACK(jynelson): `clean` expects the type, not the associated item
|
||||
// but the disambiguator logic expects the associated item.
|
||||
// Store the kind in a side channel so that only the disambiguator logic looks at it.
|
||||
return Some((
|
||||
root_res,
|
||||
format!("{}.{}", out, item_name),
|
||||
Some((kind.as_def_kind(), id)),
|
||||
));
|
||||
}
|
||||
|
||||
if ns != Namespace::ValueNS {
|
||||
return None;
|
||||
}
|
||||
debug!("looking for variants or fields named {} for {:?}", item_name, did);
|
||||
// FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?)
|
||||
// NOTE: it's different from variant_field because it resolves fields and variants,
|
||||
// not variant fields (2 path segments, not 3).
|
||||
let def = match tcx.type_of(did).kind() {
|
||||
ty::Adt(def, _) => def,
|
||||
_ => return None,
|
||||
};
|
||||
let field = if def.is_enum() {
|
||||
def.all_fields().find(|item| item.ident.name == item_name)
|
||||
} else {
|
||||
def.non_enum_variant().fields.iter().find(|item| item.ident.name == item_name)
|
||||
}?;
|
||||
let kind = if def.is_enum() { DefKind::Variant } else { DefKind::Field };
|
||||
Some((
|
||||
root_res,
|
||||
format!(
|
||||
"{}.{}",
|
||||
if def.is_enum() { "variant" } else { "structfield" },
|
||||
field.ident
|
||||
),
|
||||
Some((kind, field.did)),
|
||||
))
|
||||
}
|
||||
Res::Def(DefKind::Trait, did) => tcx
|
||||
.associated_items(did)
|
||||
|
@ -669,27 +652,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
if extra_fragment.is_some() {
|
||||
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res)))
|
||||
} else {
|
||||
let res = Res::Def(item.kind.as_def_kind(), item.def_id);
|
||||
Ok((res, Some(format!("{}.{}", kind, item_str))))
|
||||
}
|
||||
let res = Res::Def(item.kind.as_def_kind(), item.def_id);
|
||||
(res, format!("{}.{}", kind, item_name), None)
|
||||
}),
|
||||
_ => None,
|
||||
};
|
||||
res.unwrap_or_else(|| {
|
||||
if ns == Namespace::ValueNS {
|
||||
self.variant_field(path_str, module_id)
|
||||
} else {
|
||||
Err(ResolutionFailure::NotResolved {
|
||||
module_id,
|
||||
partial_res: Some(ty_res),
|
||||
unresolved: item_str.into(),
|
||||
}
|
||||
.into())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Used for reporting better errors.
|
||||
|
|
|
@ -1,19 +1,27 @@
|
|||
warning: public documentation for `DocMe` links to private item `DontDocMe`
|
||||
--> $DIR/private.rs:5:11
|
||||
--> $DIR/private.rs:7:11
|
||||
|
|
||||
LL | /// docs [DontDocMe] [DontDocMe::f]
|
||||
LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
|
||||
| ^^^^^^^^^ this item is private
|
||||
|
|
||||
= note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
|
||||
= note: this link resolves only because you passed `--document-private-items`, but will break without
|
||||
|
||||
warning: public documentation for `DocMe` links to private item `DontDocMe::f`
|
||||
--> $DIR/private.rs:5:23
|
||||
--> $DIR/private.rs:7:23
|
||||
|
|
||||
LL | /// docs [DontDocMe] [DontDocMe::f]
|
||||
LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
|
||||
| ^^^^^^^^^^^^ this item is private
|
||||
|
|
||||
= note: this link resolves only because you passed `--document-private-items`, but will break without
|
||||
|
||||
warning: 2 warnings emitted
|
||||
warning: public documentation for `DocMe` links to private item `DontDocMe::x`
|
||||
--> $DIR/private.rs:7:38
|
||||
|
|
||||
LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
|
||||
| ^^^^^^^^^^^^ this item is private
|
||||
|
|
||||
= note: this link resolves only because you passed `--document-private-items`, but will break without
|
||||
|
||||
warning: 3 warnings emitted
|
||||
|
||||
|
|
|
@ -1,19 +1,27 @@
|
|||
warning: public documentation for `DocMe` links to private item `DontDocMe`
|
||||
--> $DIR/private.rs:5:11
|
||||
--> $DIR/private.rs:7:11
|
||||
|
|
||||
LL | /// docs [DontDocMe] [DontDocMe::f]
|
||||
LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
|
||||
| ^^^^^^^^^ this item is private
|
||||
|
|
||||
= note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
|
||||
= note: this link will resolve properly if you pass `--document-private-items`
|
||||
|
||||
warning: public documentation for `DocMe` links to private item `DontDocMe::f`
|
||||
--> $DIR/private.rs:5:23
|
||||
--> $DIR/private.rs:7:23
|
||||
|
|
||||
LL | /// docs [DontDocMe] [DontDocMe::f]
|
||||
LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
|
||||
| ^^^^^^^^^^^^ this item is private
|
||||
|
|
||||
= note: this link will resolve properly if you pass `--document-private-items`
|
||||
|
||||
warning: 2 warnings emitted
|
||||
warning: public documentation for `DocMe` links to private item `DontDocMe::x`
|
||||
--> $DIR/private.rs:7:38
|
||||
|
|
||||
LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
|
||||
| ^^^^^^^^^^^^ this item is private
|
||||
|
|
||||
= note: this link will resolve properly if you pass `--document-private-items`
|
||||
|
||||
warning: 3 warnings emitted
|
||||
|
||||
|
|
|
@ -2,12 +2,16 @@
|
|||
// revisions: public private
|
||||
// [private]compile-flags: --document-private-items
|
||||
|
||||
/// docs [DontDocMe] [DontDocMe::f]
|
||||
// make sure to update `rustdoc/intra-doc/private.rs` if you update this file
|
||||
|
||||
/// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
|
||||
//~^ WARNING public documentation for `DocMe` links to private item `DontDocMe`
|
||||
//~| WARNING public documentation for `DocMe` links to private item `DontDocMe::x`
|
||||
//~| WARNING public documentation for `DocMe` links to private item `DontDocMe::f`
|
||||
// FIXME: for [private] we should also make sure the link was actually generated
|
||||
pub struct DocMe;
|
||||
struct DontDocMe;
|
||||
struct DontDocMe {
|
||||
x: usize,
|
||||
}
|
||||
|
||||
impl DontDocMe {
|
||||
fn f() {}
|
||||
|
|
|
@ -1,6 +1,17 @@
|
|||
#![crate_name = "private"]
|
||||
// compile-flags: --document-private-items
|
||||
/// docs [DontDocMe]
|
||||
|
||||
// make sure to update `rustdoc-ui/intra-doc/private.rs` if you update this file
|
||||
|
||||
/// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
|
||||
// @has private/struct.DocMe.html '//*a[@href="../private/struct.DontDocMe.html"]' 'DontDocMe'
|
||||
// @has private/struct.DocMe.html '//*a[@href="../private/struct.DontDocMe.html#method.f"]' 'DontDocMe::f'
|
||||
// @has private/struct.DocMe.html '//*a[@href="../private/struct.DontDocMe.html#structfield.x"]' 'DontDocMe::x'
|
||||
pub struct DocMe;
|
||||
struct DontDocMe;
|
||||
struct DontDocMe {
|
||||
x: usize,
|
||||
}
|
||||
|
||||
impl DontDocMe {
|
||||
fn f() {}
|
||||
}
|
||||
|
|
|
@ -45,4 +45,30 @@ fn main() {
|
|||
//~^ ERROR mismatched types
|
||||
let r = R { i: i };
|
||||
//~^ ERROR mismatched types
|
||||
|
||||
|
||||
let a = &1;
|
||||
let b = &2;
|
||||
let val: i32 = if true {
|
||||
a + 1
|
||||
} else {
|
||||
b
|
||||
//~^ ERROR mismatched types
|
||||
};
|
||||
let val: i32 = if true {
|
||||
let _ = 2;
|
||||
a + 1
|
||||
} else {
|
||||
let _ = 2;
|
||||
b
|
||||
//~^ ERROR mismatched types
|
||||
};
|
||||
let val = if true {
|
||||
*a
|
||||
} else if true {
|
||||
//~^ ERROR incompatible types
|
||||
b
|
||||
} else {
|
||||
&0
|
||||
};
|
||||
}
|
||||
|
|
|
@ -89,6 +89,43 @@ LL | let r = R { i: i };
|
|||
| expected `u32`, found `&{integer}`
|
||||
| help: consider dereferencing the borrow: `*i`
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/deref-suggestion.rs:55:9
|
||||
|
|
||||
LL | b
|
||||
| ^
|
||||
| |
|
||||
| expected `i32`, found `&{integer}`
|
||||
| help: consider dereferencing the borrow: `*b`
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/deref-suggestion.rs:63:9
|
||||
|
|
||||
LL | b
|
||||
| ^
|
||||
| |
|
||||
| expected `i32`, found `&{integer}`
|
||||
| help: consider dereferencing the borrow: `*b`
|
||||
|
||||
error[E0308]: `if` and `else` have incompatible types
|
||||
--> $DIR/deref-suggestion.rs:68:12
|
||||
|
|
||||
LL | let val = if true {
|
||||
| _______________-
|
||||
LL | | *a
|
||||
| | -- expected because of this
|
||||
LL | | } else if true {
|
||||
| |____________^
|
||||
LL | ||
|
||||
LL | || b
|
||||
LL | || } else {
|
||||
LL | || &0
|
||||
LL | || };
|
||||
| || ^
|
||||
| ||_____|
|
||||
| |______`if` and `else` have incompatible types
|
||||
| expected `i32`, found `&{integer}`
|
||||
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
|
11
src/test/ui/macros/attr-empty-expr.rs
Normal file
11
src/test/ui/macros/attr-empty-expr.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
// AST-based macro attributes expanding to an empty expression produce an error and not ICE.
|
||||
|
||||
#![feature(custom_test_frameworks)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(test)]
|
||||
|
||||
fn main() {
|
||||
let _ = #[test] 0; //~ ERROR removing an expression is not supported in this position
|
||||
let _ = #[bench] 1; //~ ERROR removing an expression is not supported in this position
|
||||
let _ = #[test_case] 2; //~ ERROR removing an expression is not supported in this position
|
||||
}
|
20
src/test/ui/macros/attr-empty-expr.stderr
Normal file
20
src/test/ui/macros/attr-empty-expr.stderr
Normal file
|
@ -0,0 +1,20 @@
|
|||
error: removing an expression is not supported in this position
|
||||
--> $DIR/attr-empty-expr.rs:8:13
|
||||
|
|
||||
LL | let _ = #[test] 0;
|
||||
| ^^^^^^^
|
||||
|
||||
error: removing an expression is not supported in this position
|
||||
--> $DIR/attr-empty-expr.rs:9:13
|
||||
|
|
||||
LL | let _ = #[bench] 1;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: removing an expression is not supported in this position
|
||||
--> $DIR/attr-empty-expr.rs:10:13
|
||||
|
|
||||
LL | let _ = #[test_case] 2;
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// Regression test for #83621.
|
||||
|
||||
extern "C" {
|
||||
static x: _; //~ ERROR: [E0121]
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,9 @@
|
|||
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
|
||||
--> $DIR/issue-83621-placeholder-static-in-extern.rs:4:15
|
||||
|
|
||||
LL | static x: _;
|
||||
| ^ not allowed in type signatures
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0121`.
|
|
@ -1 +1 @@
|
|||
Subproject commit bb1d925dab36372c6bd1fb5671bb68ce938ff009
|
||||
Subproject commit 19e09a4a54c75312aeaac04577f2d0e067463ab6
|
Loading…
Add table
Reference in a new issue