Skip to content

Rollup of 8 pull requests #83905

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Apr 6, 2021
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b5782ba
Catch a bad placeholder type error for statics in `extern`s
JohnTitor Apr 1, 2021
98ad0af
Properly suggest deref in else block
mibac138 Dec 6, 2020
e603f99
Address review comments
mibac138 Dec 17, 2020
0887944
Add additional test
LeSeulArtichaut Mar 25, 2021
fb7cf09
Don't suggest dereferencing an `else if` expression
LeSeulArtichaut Apr 1, 2021
cd22425
expand: Do not ICE when a legacy AST-based macro attribute produces a…
petrochenkov Apr 3, 2021
5f92951
rustdoc: sort search index items for compression
notriddle Apr 4, 2021
2370e3b
Get rid of unneeded `aliases` field
notriddle Apr 4, 2021
6ce9a02
:arrow_up: rust-analyzer
lnicola Apr 5, 2021
d63b3f9
Remove duplicate unwrap_or_else
jyn514 Apr 4, 2021
ac04dbd
Reduce indentation in `resolve_associated_item`
jyn514 Apr 4, 2021
3b7e654
Use more appropriate return type for `resolve_associated_item`
jyn514 Apr 4, 2021
0a351ab
Document compiler/ with -Aprivate-intra-doc-links
jyn514 Apr 5, 2021
f8653c9
Add config file for tools enabling stage1 downloads by default
jyn514 Dec 4, 2020
e5edded
Rollup merge of #83370 - jyn514:setup-tools, r=Mark-Simulacrum
JohnTitor Apr 5, 2021
d9f123a
Rollup merge of #83489 - LeSeulArtichaut:deref-else, r=davidtwco
JohnTitor Apr 5, 2021
76be7e2
Rollup merge of #83734 - JohnTitor:issue-83621, r=davidtwco
JohnTitor Apr 5, 2021
67ffbed
Rollup merge of #83814 - petrochenkov:emptyexpr, r=davidtwco
JohnTitor Apr 5, 2021
12d007d
Rollup merge of #83835 - notriddle:sort-index, r=ollie27
JohnTitor Apr 5, 2021
f93412f
Rollup merge of #83849 - jyn514:intra-doc-cleanup, r=bugadani
JohnTitor Apr 5, 2021
fb6eb4a
Rollup merge of #83881 - lnicola:rust-analyzer-2021-04-05, r=jonas-sc…
JohnTitor Apr 5, 2021
d8c04b1
Rollup merge of #83885 - jyn514:private-links, r=Mark-Simulacrum
JohnTitor Apr 5, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions compiler/rustc_errors/src/diagnostic_builder.rs
Original file line number Diff line number Diff line change
@@ -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
9 changes: 8 additions & 1 deletion compiler/rustc_expand/src/expand.rs
Original file line number Diff line number Diff line change
@@ -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();
1 change: 1 addition & 0 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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};

28 changes: 28 additions & 0 deletions compiler/rustc_typeck/src/check/demand.rs
Original file line number Diff line number Diff line change
@@ -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)
};
10 changes: 8 additions & 2 deletions compiler/rustc_typeck/src/collect.rs
Original file line number Diff line number Diff line change
@@ -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);
}
_ => (),
}
}
}
3 changes: 1 addition & 2 deletions src/bootstrap/defaults/config.compiler.toml
Original file line number Diff line number Diff line change
@@ -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 changes: 16 additions & 0 deletions src/bootstrap/defaults/config.tools.toml
Original file line number Diff line number Diff line change
@@ -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"
2 changes: 2 additions & 0 deletions src/bootstrap/doc.rs
Original file line number Diff line number Diff line change
@@ -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");
20 changes: 17 additions & 3 deletions src/bootstrap/setup.rs
Original file line number Diff line number Diff line change
@@ -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"],
};
4 changes: 2 additions & 2 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
@@ -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()
}
}

13 changes: 1 addition & 12 deletions src/librustdoc/formats/cache.rs
Original file line number Diff line number Diff line change
@@ -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 => {
31 changes: 22 additions & 9 deletions src/librustdoc/html/render/cache.rs
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
@@ -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.
237 changes: 102 additions & 135 deletions src/librustdoc/passes/collect_intra_doc_links.rs
Original file line number Diff line number Diff line change
@@ -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())
};
};
})
}

/// 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;

let res = match ty_res {
Res::Primitive(prim) => Some(
self.resolve_primitive_associated_item(prim, ns, module_id, item_name, item_str),
),
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.
18 changes: 13 additions & 5 deletions src/test/rustdoc-ui/intra-doc/private.private.stderr
Original file line number Diff line number Diff line change
@@ -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

18 changes: 13 additions & 5 deletions src/test/rustdoc-ui/intra-doc/private.public.stderr
Original file line number Diff line number Diff line change
@@ -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

10 changes: 7 additions & 3 deletions src/test/rustdoc-ui/intra-doc/private.rs
Original file line number Diff line number Diff line change
@@ -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() {}
15 changes: 13 additions & 2 deletions src/test/rustdoc/intra-doc/private.rs
Original file line number Diff line number Diff line change
@@ -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() {}
}
26 changes: 26 additions & 0 deletions src/test/ui/deref-suggestion.rs
Original file line number Diff line number Diff line change
@@ -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
};
}
39 changes: 38 additions & 1 deletion src/test/ui/deref-suggestion.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 11 additions & 0 deletions src/test/ui/macros/attr-empty-expr.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 20 additions & 0 deletions src/test/ui/macros/attr-empty-expr.stderr
Original file line number Diff line number Diff line change
@@ -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

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Regression test for #83621.

extern "C" {
static x: _; //~ ERROR: [E0121]
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -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`.
2 changes: 1 addition & 1 deletion src/tools/rust-analyzer