Skip to content

Commit

Permalink
Auto merge of rust-lang#87640 - JohnTitor:rollup-yq24nq5, r=JohnTitor
Browse files Browse the repository at this point in the history
Rollup of 9 pull requests

Successful merges:

 - rust-lang#86072 (Cross compiling rustc_llvm on Darwin requires zlib.)
 - rust-lang#87385 (Make `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` warn by default)
 - rust-lang#87547 (Add missing examples for NonNull)
 - rust-lang#87557 (Fix issue with autofix for ambiguous associated function from Rust 2021 prelude when struct is generic)
 - rust-lang#87559 (Tweak borrowing suggestion in `for` loop)
 - rust-lang#87596 (Add warning when whitespace is not skipped after an escaped newline)
 - rust-lang#87606 (Add some TAIT-related regression tests)
 - rust-lang#87609 (Add docs about performance and `Iterator::map` to `[T; N]::map`)
 - rust-lang#87616 (Fix missing word in rustdoc book)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Jul 30, 2021
2 parents ef9549b + 8d5291c commit 1f0a591
Show file tree
Hide file tree
Showing 43 changed files with 577 additions and 94 deletions.
24 changes: 20 additions & 4 deletions compiler/rustc_ast/src/util/literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@ impl LitKind {
unescape_literal(&s, Mode::Str, &mut |_, unescaped_char| {
match unescaped_char {
Ok(c) => buf.push(c),
Err(_) => error = Err(LitError::LexerError),
Err(err) => {
if err.is_fatal() {
error = Err(LitError::LexerError);
}
}
}
});
error?;
Expand All @@ -83,7 +87,11 @@ impl LitKind {
unescape_literal(&s, Mode::RawStr, &mut |_, unescaped_char| {
match unescaped_char {
Ok(c) => buf.push(c),
Err(_) => error = Err(LitError::LexerError),
Err(err) => {
if err.is_fatal() {
error = Err(LitError::LexerError);
}
}
}
});
error?;
Expand All @@ -100,7 +108,11 @@ impl LitKind {
unescape_byte_literal(&s, Mode::ByteStr, &mut |_, unescaped_byte| {
match unescaped_byte {
Ok(c) => buf.push(c),
Err(_) => error = Err(LitError::LexerError),
Err(err) => {
if err.is_fatal() {
error = Err(LitError::LexerError);
}
}
}
});
error?;
Expand All @@ -114,7 +126,11 @@ impl LitKind {
unescape_byte_literal(&s, Mode::RawByteStr, &mut |_, unescaped_byte| {
match unescaped_byte {
Ok(c) => buf.push(c),
Err(_) => error = Err(LitError::LexerError),
Err(err) => {
if err.is_fatal() {
error = Err(LitError::LexerError);
}
}
}
});
error?;
Expand Down
26 changes: 19 additions & 7 deletions compiler/rustc_expand/src/mbe/macro_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ crate struct ParserAnyMacro<'a> {
lint_node_id: NodeId,
is_trailing_mac: bool,
arm_span: Span,
/// Whether or not this macro is defined in the current crate
is_local: bool,
}

crate fn annotate_err_with_kind(
Expand Down Expand Up @@ -124,6 +126,7 @@ impl<'a> ParserAnyMacro<'a> {
lint_node_id,
arm_span,
is_trailing_mac,
is_local,
} = *self;
let snapshot = &mut parser.clone();
let fragment = match parse_ast_fragment(parser, kind) {
Expand All @@ -138,13 +141,15 @@ impl<'a> ParserAnyMacro<'a> {
// `macro_rules! m { () => { panic!(); } }` isn't parsed by `.parse_expr()`,
// but `m!()` is allowed in expression positions (cf. issue #34706).
if kind == AstFragmentKind::Expr && parser.token == token::Semi {
parser.sess.buffer_lint_with_diagnostic(
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
parser.token.span,
lint_node_id,
"trailing semicolon in macro used in expression position",
BuiltinLintDiagnostics::TrailingMacro(is_trailing_mac, macro_ident),
);
if is_local {
parser.sess.buffer_lint_with_diagnostic(
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
parser.token.span,
lint_node_id,
"trailing semicolon in macro used in expression position",
BuiltinLintDiagnostics::TrailingMacro(is_trailing_mac, macro_ident),
);
}
parser.bump();
}

Expand All @@ -162,6 +167,7 @@ struct MacroRulesMacroExpander {
lhses: Vec<mbe::TokenTree>,
rhses: Vec<mbe::TokenTree>,
valid: bool,
is_local: bool,
}

impl TTMacroExpander for MacroRulesMacroExpander {
Expand All @@ -183,6 +189,7 @@ impl TTMacroExpander for MacroRulesMacroExpander {
input,
&self.lhses,
&self.rhses,
self.is_local,
)
}
}
Expand Down Expand Up @@ -210,6 +217,7 @@ fn generic_extension<'cx>(
arg: TokenStream,
lhses: &[mbe::TokenTree],
rhses: &[mbe::TokenTree],
is_local: bool,
) -> Box<dyn MacResult + 'cx> {
let sess = &cx.sess.parse_sess;

Expand Down Expand Up @@ -311,6 +319,7 @@ fn generic_extension<'cx>(
lint_node_id: cx.current_expansion.lint_node_id,
is_trailing_mac: cx.current_expansion.is_trailing_mac,
arm_span,
is_local,
});
}
Failure(token, msg) => match best_failure {
Expand Down Expand Up @@ -544,6 +553,9 @@ pub fn compile_declarative_macro(
lhses,
rhses,
valid,
// Macros defined in the current crate have a real node id,
// whereas macros from an external crate have a dummy id.
is_local: def.id != DUMMY_NODE_ID,
}))
}

Expand Down
34 changes: 30 additions & 4 deletions compiler/rustc_lexer/src/unescape.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::str::Chars;
#[cfg(test)]
mod tests;

/// Errors that can occur during string unescaping.
/// Errors and warnings that can occur during string unescaping.
#[derive(Debug, PartialEq, Eq)]
pub enum EscapeError {
/// Expected 1 char, but 0 were found.
Expand Down Expand Up @@ -56,6 +56,20 @@ pub enum EscapeError {
NonAsciiCharInByte,
/// Non-ascii character in byte string literal.
NonAsciiCharInByteString,

/// After a line ending with '\', the next line contains whitespace
/// characters that are not skipped.
UnskippedWhitespaceWarning,
}

impl EscapeError {
/// Returns true for actual errors, as opposed to warnings.
pub fn is_fatal(&self) -> bool {
match self {
EscapeError::UnskippedWhitespaceWarning => false,
_ => true,
}
}
}

/// Takes a contents of a literal (without quotes) and produces a
Expand Down Expand Up @@ -283,7 +297,7 @@ where
// if unescaped '\' character is followed by '\n'.
// For details see [Rust language reference]
// (https://doc.rust-lang.org/reference/tokens.html#string-literals).
skip_ascii_whitespace(&mut chars);
skip_ascii_whitespace(&mut chars, start, callback);
continue;
}
_ => scan_escape(first_char, &mut chars, mode),
Expand All @@ -297,13 +311,25 @@ where
callback(start..end, unescaped_char);
}

fn skip_ascii_whitespace(chars: &mut Chars<'_>) {
fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut F)
where
F: FnMut(Range<usize>, Result<char, EscapeError>),
{
let str = chars.as_str();
let first_non_space = str
.bytes()
.position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
.unwrap_or(str.len());
*chars = str[first_non_space..].chars()
let tail = &str[first_non_space..];
if let Some(c) = tail.chars().nth(0) {
// For error reporting, we would like the span to contain the character that was not
// skipped. The +1 is necessary to account for the leading \ that started the escape.
let end = start + first_non_space + c.len_utf8() + 1;
if c.is_whitespace() {
callback(start..end, Err(EscapeError::UnskippedWhitespaceWarning));
}
}
*chars = tail.chars();
}
}

Expand Down
19 changes: 19 additions & 0 deletions compiler/rustc_lexer/src/unescape/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,25 @@ fn test_unescape_char_good() {
check(r"\u{1F63b}", '😻');
}

#[test]
fn test_unescape_str_warn() {
fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)]) {
let mut unescaped = Vec::with_capacity(literal.len());
unescape_literal(literal, Mode::Str, &mut |range, res| unescaped.push((range, res)));
assert_eq!(unescaped, expected);
}

check(
"\\\n \u{a0} x",
&[
(0..5, Err(EscapeError::UnskippedWhitespaceWarning)),
(3..5, Ok('\u{a0}')),
(5..6, Ok(' ')),
(6..7, Ok('x')),
],
);
}

#[test]
fn test_unescape_str_good() {
fn check(literal_text: &str, expected: &str) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2799,7 +2799,7 @@ declare_lint! {
/// [issue #79813]: https://github.com/rust-lang/rust/issues/79813
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
Allow,
Warn,
"trailing semicolon in macro body used as expression",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #79813 <https://github.com/rust-lang/rust/issues/79813>",
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_llvm/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ fn main() {
} else if target.contains("windows-gnu") {
println!("cargo:rustc-link-lib=shell32");
println!("cargo:rustc-link-lib=uuid");
} else if target.contains("netbsd") || target.contains("haiku") {
} else if target.contains("netbsd") || target.contains("haiku") || target.contains("darwin") {
println!("cargo:rustc-link-lib=z");
}
cmd.args(&components);
Expand Down
69 changes: 39 additions & 30 deletions compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_middle::mir::*;
use rustc_middle::ty;
use rustc_span::source_map::DesugaringKind;
use rustc_span::{sym, Span};
use rustc_span::{sym, Span, DUMMY_SP};
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;

use crate::borrow_check::diagnostics::UseSpans;
use crate::borrow_check::prefixes::PrefixSet;
Expand Down Expand Up @@ -384,36 +385,44 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
};
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
let def_id = match *move_place.ty(self.body, self.infcx.tcx).ty.kind() {
ty::Adt(self_def, _) => self_def.did,
ty::Foreign(def_id)
| ty::FnDef(def_id, _)
| ty::Closure(def_id, _)
| ty::Generator(def_id, ..)
| ty::Opaque(def_id, _) => def_id,
_ => return err,
let ty = move_place.ty(self.body, self.infcx.tcx).ty;
let def_id = match *ty.kind() {
ty::Adt(self_def, _) => self_def.did,
ty::Foreign(def_id)
| ty::FnDef(def_id, _)
| ty::Closure(def_id, _)
| ty::Generator(def_id, ..)
| ty::Opaque(def_id, _) => def_id,
_ => return err,
};
let is_option = self.infcx.tcx.is_diagnostic_item(sym::option_type, def_id);
let is_result = self.infcx.tcx.is_diagnostic_item(sym::result_type, def_id);
if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
err.span_suggestion_verbose(
span.shrink_to_hi(),
&format!(
"consider borrowing the `{}`'s content",
if is_option { "Option" } else { "Result" }
),
".as_ref()".to_string(),
Applicability::MaybeIncorrect,
);
} else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) {
let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
Some(def_id) => type_known_to_meet_bound_modulo_regions(
&self.infcx,
self.param_env,
self.infcx.tcx.mk_imm_ref(self.infcx.tcx.lifetimes.re_erased, ty),
def_id,
DUMMY_SP,
),
_ => false,
};
let is_option = self.infcx.tcx.is_diagnostic_item(sym::option_type, def_id);
let is_result = self.infcx.tcx.is_diagnostic_item(sym::result_type, def_id);
if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
err.span_suggestion(
span,
&format!(
"consider borrowing the `{}`'s content",
if is_option { "Option" } else { "Result" }
),
format!("{}.as_ref()", snippet),
Applicability::MaybeIncorrect,
);
} else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_)))
&& self.infcx.tcx.is_diagnostic_item(sym::vec_type, def_id)
{
// FIXME: suggest for anything that implements `IntoIterator`.
err.span_suggestion(
span,
"consider iterating over a slice of the `Vec<_>`'s content",
format!("&{}", snippet),
if suggest {
err.span_suggestion_verbose(
span.shrink_to_lo(),
&format!("consider iterating over a slice of the `{}`'s content", ty),
"&".to_string(),
Applicability::MaybeIncorrect,
);
}
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,12 @@ pub(crate) fn emit_unescape_error(
let msg = "invalid trailing slash in literal";
handler.struct_span_err(span, msg).span_label(span, msg).emit();
}
EscapeError::UnskippedWhitespaceWarning => {
let (c, char_span) = last_char();
let msg =
format!("non-ASCII whitespace symbol '{}' is not skipped", c.escape_unicode());
handler.struct_span_warn(span, &msg).span_label(char_span, &msg).emit();
}
}
}

Expand Down
21 changes: 18 additions & 3 deletions compiler/rustc_typeck/src/check/method/prelude2021.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use rustc_ast::Mutability;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{Ref, Ty};
use rustc_middle::ty::{Adt, Ref, Ty};
use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
use rustc_span::symbol::kw::Underscore;
use rustc_span::symbol::{sym, Ident};
Expand Down Expand Up @@ -255,16 +255,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
method_name.name
));

let self_ty = self
let self_ty_name = self
.sess()
.source_map()
.span_to_snippet(self_ty_span)
.unwrap_or_else(|_| self_ty.to_string());

let self_ty_generics_count = match self_ty.kind() {
// Get the number of generics the self type has (if an Adt) unless we can determine that
// the user has written the self type with generics already which we (naively) do by looking
// for a "<" in `self_ty_name`.
Adt(def, _) if !self_ty_name.contains("<") => self.tcx.generics_of(def.did).count(),
_ => 0,
};
let self_ty_generics = if self_ty_generics_count > 0 {
format!("<{}>", vec!["_"; self_ty_generics_count].join(", "))
} else {
String::new()
};
lint.span_suggestion(
span,
"disambiguate the associated function",
format!("<{} as {}>::{}", self_ty, trait_name, method_name.name,),
format!(
"<{}{} as {}>::{}",
self_ty_name, self_ty_generics, trait_name, method_name.name,
),
Applicability::MachineApplicable,
);

Expand Down
Loading

0 comments on commit 1f0a591

Please sign in to comment.