Skip to content
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

Rollup of 8 pull requests #101736

Merged
merged 17 commits into from
Sep 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
315d12d
Fix ReErased leaking into typeck due to typeof recovery
compiler-errors Aug 5, 2022
2126622
Add test for #101211
oMisaki Sep 11, 2022
cb02b64
constify `CStr` methods
WaffleLapkin Aug 8, 2022
2b7fb8d
Impove diagnostic for .await-ing non-futures
Sep 12, 2022
9139891
Allow unauthenticated users to add the `const-hack` label
fee1-dead Sep 12, 2022
fd1a399
Allow tool-lints to specify a feature-gate too
Nemo157 Sep 12, 2022
84ca399
rustdoc: improve rustdoc HTML suggestions handling of nested generics
notriddle Sep 12, 2022
72cf46a
Feature gate the rustdoc::missing_doc_code_examples lint
Nemo157 Sep 12, 2022
29f789f
rustdoc: fix treatment of backslash-escaped HTML
notriddle Sep 12, 2022
b7504d6
Rollup merge of #100185 - compiler-errors:issue-100183, r=wesleywiser
GuillaumeGomez Sep 12, 2022
7fc3183
Rollup merge of #100291 - WaffleLapkin:cstr_const_methods, r=oli-obk
GuillaumeGomez Sep 12, 2022
5727331
Rollup merge of #101677 - winxpqq955:issue-101211, r=fee1-dead
GuillaumeGomez Sep 12, 2022
8dc4b26
Rollup merge of #101723 - lukas-code:await-diag, r=compiler-errors
GuillaumeGomez Sep 12, 2022
bbe23e8
Rollup merge of #101724 - fee1-dead-contrib:triage-const-hack, r=oli-obk
GuillaumeGomez Sep 12, 2022
05a267f
Rollup merge of #101731 - notriddle:notriddle/more-improved-html-chec…
GuillaumeGomez Sep 12, 2022
ac92cc8
Rollup merge of #101732 - Nemo157:gate-rustdoc-missing-examples, r=Gu…
GuillaumeGomez Sep 12, 2022
031a2f8
Rollup merge of #101735 - notriddle:notriddle/backslash-escaped-html,…
GuillaumeGomez Sep 12, 2022
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
12 changes: 9 additions & 3 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,13 +146,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
),
ExprKind::Await(ref expr) => {
let span = if expr.span.hi() < e.span.hi() {
expr.span.shrink_to_hi().with_hi(e.span.hi())
let dot_await_span = if expr.span.hi() < e.span.hi() {
let span_with_whitespace = self
.tcx
.sess
.source_map()
.span_extend_while(expr.span, char::is_whitespace)
.unwrap_or(expr.span);
span_with_whitespace.shrink_to_hi().with_hi(e.span.hi())
} else {
// this is a recovered `await expr`
e.span
};
self.lower_expr_await(span, expr)
self.lower_expr_await(dot_await_span, expr)
}
ExprKind::Closure(
ref binder,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ declare_features! (
(active, rustc_private, "1.0.0", Some(27812), None),
/// Allows using internal rustdoc features like `doc(primitive)` or `doc(keyword)`.
(active, rustdoc_internals, "1.58.0", Some(90418), None),
/// Allows using the `rustdoc::missing_doc_code_examples` lint
(active, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730), None),
/// Allows using `#[start]` on a function indicating that it is the program entrypoint.
(active, start, "1.0.0", Some(29633), None),
/// Allows using `#[structural_match]` which indicates that a type is structurally matchable.
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_lint/src/levels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,8 +440,10 @@ impl<'s> LintLevelsBuilder<'s> {
sp,
reason,
);
for id in ids {
self.insert_spec(*id, (level, src));
for &id in ids {
if self.check_gated_lint(id, attr.span) {
self.insert_spec(id, (level, src));
}
}
if let Level::Expect(expect_id) = level {
self.lint_expectations.push((
Expand Down
10 changes: 7 additions & 3 deletions compiler/rustc_lint_defs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -658,18 +658,21 @@ macro_rules! declare_lint {
macro_rules! declare_tool_lint {
(
$(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level: ident, $desc: expr
$(, @feature_gate = $gate:expr;)?
) => (
$crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false}
$crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, false $(, @feature_gate = $gate;)?}
);
(
$(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
report_in_external_macro: $rep:expr
$(, @feature_gate = $gate:expr;)?
) => (
$crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep}
$crate::declare_tool_lint!{$(#[$attr])* $vis $tool::$NAME, $Level, $desc, $rep $(, @feature_gate = $gate;)?}
);
(
$(#[$attr:meta])* $vis:vis $tool:ident ::$NAME:ident, $Level:ident, $desc:expr,
$external:expr
$(, @feature_gate = $gate:expr;)?
) => (
$(#[$attr])*
$vis static $NAME: &$crate::Lint = &$crate::Lint {
Expand All @@ -680,8 +683,9 @@ macro_rules! declare_tool_lint {
report_in_external_macro: $external,
future_incompatible: None,
is_plugin: true,
feature_gate: None,
$(feature_gate: Some($gate),)?
crate_level_only: false,
..$crate::Lint::default_fields_for_macro()
};
);
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1292,6 +1292,7 @@ symbols! {
rustc_variance,
rustdoc,
rustdoc_internals,
rustdoc_missing_doc_code_examples,
rustfmt,
rvalue_static_promotion,
s,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1160,8 +1160,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// and if not maybe suggest doing something else? If we kept the expression around we
// could also check if it is an fn call (very likely) and suggest changing *that*, if
// it is from the local crate.
err.span_suggestion_verbose(
expr.span.shrink_to_hi().with_hi(span.hi()),
err.span_suggestion(
span,
"remove the `.await`",
"",
Applicability::MachineApplicable,
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_typeck/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2672,7 +2672,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.normalize_ty(ast_ty.span, array_ty)
}
hir::TyKind::Typeof(ref e) => {
let ty = tcx.type_of(tcx.hir().local_def_id(e.hir_id));
let ty_erased = tcx.type_of(tcx.hir().local_def_id(e.hir_id));
let ty = tcx.fold_regions(ty_erased, |r, _| {
if r.is_erased() { tcx.lifetimes.re_static } else { r }
});
let span = ast_ty.span;
tcx.sess.emit_err(TypeofReservedKeywordUsed {
span,
Expand Down
19 changes: 12 additions & 7 deletions library/core/src/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,10 @@ enum FromBytesWithNulErrorKind {
}

impl FromBytesWithNulError {
fn interior_nul(pos: usize) -> FromBytesWithNulError {
const fn interior_nul(pos: usize) -> FromBytesWithNulError {
FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) }
}
fn not_nul_terminated() -> FromBytesWithNulError {
const fn not_nul_terminated() -> FromBytesWithNulError {
FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated }
}

Expand Down Expand Up @@ -294,7 +294,8 @@ impl CStr {
/// ```
///
#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
#[rustc_const_unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
let nul_pos = memchr::memchr(0, bytes);
match nul_pos {
Some(nul_pos) => {
Expand Down Expand Up @@ -343,7 +344,8 @@ impl CStr {
/// assert!(cstr.is_err());
/// ```
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
#[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
let nul_pos = memchr::memchr(0, bytes);
match nul_pos {
Some(nul_pos) if nul_pos + 1 == bytes.len() => {
Expand Down Expand Up @@ -493,7 +495,8 @@ impl CStr {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_bytes(&self) -> &[u8] {
#[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
pub const fn to_bytes(&self) -> &[u8] {
let bytes = self.to_bytes_with_nul();
// SAFETY: to_bytes_with_nul returns slice with length at least 1
unsafe { bytes.get_unchecked(..bytes.len() - 1) }
Expand All @@ -520,7 +523,8 @@ impl CStr {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_bytes_with_nul(&self) -> &[u8] {
#[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
pub const fn to_bytes_with_nul(&self) -> &[u8] {
// SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s
// is safe on all supported targets.
unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
Expand All @@ -543,7 +547,8 @@ impl CStr {
/// assert_eq!(cstr.to_str(), Ok("foo"));
/// ```
#[stable(feature = "cstr_to_str", since = "1.4.0")]
pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
#[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
pub const fn to_str(&self) -> Result<&str, str::Utf8Error> {
// N.B., when `CStr` is changed to perform the length check in `.to_bytes()`
// instead of in `from_ptr()`, it may be worth considering if this should
// be rewritten to do the UTF-8 check inline with the length calculation
Expand Down
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@
#![feature(const_slice_from_ref)]
#![feature(const_slice_index)]
#![feature(const_is_char_boundary)]
#![feature(const_cstr_methods)]
//
// Language features:
#![feature(abi_unadjusted)]
Expand Down
29 changes: 24 additions & 5 deletions library/core/src/slice/memchr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch

use crate::cmp;
use crate::intrinsics;
use crate::mem;

const LO_USIZE: usize = usize::repeat_u8(0x01);
Expand Down Expand Up @@ -35,13 +36,31 @@ fn repeat_byte(b: u8) -> usize {
/// Returns the first index matching the byte `x` in `text`.
#[must_use]
#[inline]
pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
// Fast path for small slices
if text.len() < 2 * USIZE_BYTES {
return text.iter().position(|elt| *elt == x);
pub const fn memchr(x: u8, text: &[u8]) -> Option<usize> {
#[inline]
fn rt_impl(x: u8, text: &[u8]) -> Option<usize> {
// Fast path for small slices
if text.len() < 2 * USIZE_BYTES {
return text.iter().position(|elt| *elt == x);
}

memchr_general_case(x, text)
}

const fn const_impl(x: u8, bytes: &[u8]) -> Option<usize> {
let mut i = 0;
while i < bytes.len() {
if bytes[i] == x {
return Some(i);
}
i += 1;
}

None
}

memchr_general_case(x, text)
// SAFETY: The const and runtime versions have identical behavior
unsafe { intrinsics::const_eval_select((x, text), const_impl, rt_impl) }
}

fn memchr_general_case(x: u8, text: &[u8]) -> Option<usize> {
Expand Down
9 changes: 7 additions & 2 deletions src/librustdoc/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,13 @@ where
}

macro_rules! declare_rustdoc_lint {
($(#[$attr:meta])* $name: ident, $level: ident, $descr: literal $(,)?) => {
(
$(#[$attr:meta])* $name: ident, $level: ident, $descr: literal $(,)?
$(@feature_gate = $gate:expr;)?
) => {
declare_tool_lint! {
$(#[$attr])* pub rustdoc::$name, $level, $descr
$(, @feature_gate = $gate;)?
}
}
}
Expand Down Expand Up @@ -123,7 +127,8 @@ declare_rustdoc_lint! {
/// [rustdoc book]: ../../../rustdoc/lints.html#missing_doc_code_examples
MISSING_DOC_CODE_EXAMPLES,
Allow,
"detects publicly-exported items without code samples in their documentation"
"detects publicly-exported items without code samples in their documentation",
@feature_gate = rustc_span::symbol::sym::rustdoc_missing_doc_code_examples;
}

declare_rustdoc_lint! {
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/passes/check_doc_test_visibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ pub(crate) fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item

find_testable_code(dox, &mut tests, ErrorCodes::No, false, None);

if tests.found_tests == 0 && cx.tcx.sess.is_nightly_build() {
if tests.found_tests == 0 && cx.tcx.features().rustdoc_missing_doc_code_examples {
if should_have_doc_example(cx, item) {
debug!("reporting error for {:?} (hir_id={:?})", item, hir_id);
let sp = item.attr_span(cx.tcx);
Expand Down
85 changes: 81 additions & 4 deletions src/librustdoc/passes/html_tags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,34 @@ fn extract_path_backwards(text: &str, end_pos: usize) -> Option<usize> {
if current_pos == end_pos { None } else { Some(current_pos) }
}

fn extract_path_forward(text: &str, start_pos: usize) -> Option<usize> {
use rustc_lexer::{is_id_continue, is_id_start};
let mut current_pos = start_pos;
loop {
if current_pos < text.len() && text[current_pos..].starts_with("::") {
current_pos += 2;
} else {
break;
}
let mut chars = text[current_pos..].chars();
if let Some(c) = chars.next() {
if is_id_start(c) {
current_pos += c.len_utf8();
} else {
break;
}
}
while let Some(c) = chars.next() {
if is_id_continue(c) {
current_pos += c.len_utf8();
} else {
break;
}
}
}
if current_pos == start_pos { None } else { Some(current_pos) }
}

fn is_valid_for_html_tag_name(c: char, is_empty: bool) -> bool {
// https://spec.commonmark.org/0.30/#raw-html
//
Expand Down Expand Up @@ -218,19 +246,68 @@ impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> {
// If a tag looks like `<this>`, it might actually be a generic.
// We don't try to detect stuff `<like, this>` because that's not valid HTML,
// and we don't try to detect stuff `<like this>` because that's not valid Rust.
if let Some(Some(generics_start)) = (is_open_tag
&& dox[..range.end].ends_with('>'))
let mut generics_end = range.end;
if let Some(Some(mut generics_start)) = (is_open_tag
&& dox[..generics_end].ends_with('>'))
.then(|| extract_path_backwards(&dox, range.start))
{
while generics_start != 0
&& generics_end < dox.len()
&& dox.as_bytes()[generics_start - 1] == b'<'
&& dox.as_bytes()[generics_end] == b'>'
{
generics_end += 1;
generics_start -= 1;
if let Some(new_start) = extract_path_backwards(&dox, generics_start) {
generics_start = new_start;
}
if let Some(new_end) = extract_path_forward(&dox, generics_end) {
generics_end = new_end;
}
}
if let Some(new_end) = extract_path_forward(&dox, generics_end) {
generics_end = new_end;
}
let generics_sp = match super::source_span_for_markdown_range(
tcx,
&dox,
&(generics_start..range.end),
&(generics_start..generics_end),
&item.attrs,
) {
Some(sp) => sp,
None => item.attr_span(tcx),
};
// Sometimes, we only extract part of a path. For example, consider this:
//
// <[u32] as IntoIter<u32>>::Item
// ^^^^^ unclosed HTML tag `u32`
//
// We don't have any code for parsing fully-qualified trait paths.
// In theory, we could add it, but doing it correctly would require
// parsing the entire path grammar, which is problematic because of
// overlap between the path grammar and Markdown.
//
// The example above shows that ambiguity. Is `[u32]` intended to be an
// intra-doc link to the u32 primitive, or is it intended to be a slice?
//
// If the below conditional were removed, we would suggest this, which is
// not what the user probably wants.
//
// <[u32] as `IntoIter<u32>`>::Item
//
// We know that the user actually wants to wrap the whole thing in a code
// block, but the only reason we know that is because `u32` does not, in
// fact, implement IntoIter. If the example looks like this:
//
// <[Vec<i32>] as IntoIter<i32>::Item
//
// The ideal fix would be significantly different.
if (generics_start > 0 && dox.as_bytes()[generics_start - 1] == b'<')
|| (generics_end < dox.len() && dox.as_bytes()[generics_end] == b'>')
{
diag.emit();
return;
}
// multipart form is chosen here because ``Vec<i32>`` would be confusing.
diag.multipart_suggestion(
"try marking as source code",
Expand Down Expand Up @@ -278,7 +355,7 @@ impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> {
for (event, range) in p {
match event {
Event::Start(Tag::CodeBlock(_)) => in_code_block = true,
Event::Html(text) | Event::Text(text) if !in_code_block => {
Event::Html(text) if !in_code_block => {
extract_tags(&mut tags, &text, range, &mut is_in_comment, &report_diag)
}
Event::End(Tag::CodeBlock(_)) => in_code_block = false,
Expand Down
1 change: 1 addition & 0 deletions src/test/rustdoc-ui/check-fail.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// compile-flags: -Z unstable-options --check

#![feature(rustdoc_missing_doc_code_examples)]
#![deny(missing_docs)]
#![deny(rustdoc::all)]

Expand Down
Loading