Skip to content

Commit 1f0a591

Browse files
committed
Auto merge of #87640 - JohnTitor:rollup-yq24nq5, r=JohnTitor
Rollup of 9 pull requests Successful merges: - #86072 (Cross compiling rustc_llvm on Darwin requires zlib.) - #87385 (Make `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` warn by default) - #87547 (Add missing examples for NonNull) - #87557 (Fix issue with autofix for ambiguous associated function from Rust 2021 prelude when struct is generic) - #87559 (Tweak borrowing suggestion in `for` loop) - #87596 (Add warning when whitespace is not skipped after an escaped newline) - #87606 (Add some TAIT-related regression tests) - #87609 (Add docs about performance and `Iterator::map` to `[T; N]::map`) - #87616 (Fix missing word in rustdoc book) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents ef9549b + 8d5291c commit 1f0a591

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+577
-94
lines changed

compiler/rustc_ast/src/util/literal.rs

+20-4
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ impl LitKind {
6363
unescape_literal(&s, Mode::Str, &mut |_, unescaped_char| {
6464
match unescaped_char {
6565
Ok(c) => buf.push(c),
66-
Err(_) => error = Err(LitError::LexerError),
66+
Err(err) => {
67+
if err.is_fatal() {
68+
error = Err(LitError::LexerError);
69+
}
70+
}
6771
}
6872
});
6973
error?;
@@ -83,7 +87,11 @@ impl LitKind {
8387
unescape_literal(&s, Mode::RawStr, &mut |_, unescaped_char| {
8488
match unescaped_char {
8589
Ok(c) => buf.push(c),
86-
Err(_) => error = Err(LitError::LexerError),
90+
Err(err) => {
91+
if err.is_fatal() {
92+
error = Err(LitError::LexerError);
93+
}
94+
}
8795
}
8896
});
8997
error?;
@@ -100,7 +108,11 @@ impl LitKind {
100108
unescape_byte_literal(&s, Mode::ByteStr, &mut |_, unescaped_byte| {
101109
match unescaped_byte {
102110
Ok(c) => buf.push(c),
103-
Err(_) => error = Err(LitError::LexerError),
111+
Err(err) => {
112+
if err.is_fatal() {
113+
error = Err(LitError::LexerError);
114+
}
115+
}
104116
}
105117
});
106118
error?;
@@ -114,7 +126,11 @@ impl LitKind {
114126
unescape_byte_literal(&s, Mode::RawByteStr, &mut |_, unescaped_byte| {
115127
match unescaped_byte {
116128
Ok(c) => buf.push(c),
117-
Err(_) => error = Err(LitError::LexerError),
129+
Err(err) => {
130+
if err.is_fatal() {
131+
error = Err(LitError::LexerError);
132+
}
133+
}
118134
}
119135
});
120136
error?;

compiler/rustc_expand/src/mbe/macro_rules.rs

+19-7
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ crate struct ParserAnyMacro<'a> {
4545
lint_node_id: NodeId,
4646
is_trailing_mac: bool,
4747
arm_span: Span,
48+
/// Whether or not this macro is defined in the current crate
49+
is_local: bool,
4850
}
4951

5052
crate fn annotate_err_with_kind(
@@ -124,6 +126,7 @@ impl<'a> ParserAnyMacro<'a> {
124126
lint_node_id,
125127
arm_span,
126128
is_trailing_mac,
129+
is_local,
127130
} = *self;
128131
let snapshot = &mut parser.clone();
129132
let fragment = match parse_ast_fragment(parser, kind) {
@@ -138,13 +141,15 @@ impl<'a> ParserAnyMacro<'a> {
138141
// `macro_rules! m { () => { panic!(); } }` isn't parsed by `.parse_expr()`,
139142
// but `m!()` is allowed in expression positions (cf. issue #34706).
140143
if kind == AstFragmentKind::Expr && parser.token == token::Semi {
141-
parser.sess.buffer_lint_with_diagnostic(
142-
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
143-
parser.token.span,
144-
lint_node_id,
145-
"trailing semicolon in macro used in expression position",
146-
BuiltinLintDiagnostics::TrailingMacro(is_trailing_mac, macro_ident),
147-
);
144+
if is_local {
145+
parser.sess.buffer_lint_with_diagnostic(
146+
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
147+
parser.token.span,
148+
lint_node_id,
149+
"trailing semicolon in macro used in expression position",
150+
BuiltinLintDiagnostics::TrailingMacro(is_trailing_mac, macro_ident),
151+
);
152+
}
148153
parser.bump();
149154
}
150155

@@ -162,6 +167,7 @@ struct MacroRulesMacroExpander {
162167
lhses: Vec<mbe::TokenTree>,
163168
rhses: Vec<mbe::TokenTree>,
164169
valid: bool,
170+
is_local: bool,
165171
}
166172

167173
impl TTMacroExpander for MacroRulesMacroExpander {
@@ -183,6 +189,7 @@ impl TTMacroExpander for MacroRulesMacroExpander {
183189
input,
184190
&self.lhses,
185191
&self.rhses,
192+
self.is_local,
186193
)
187194
}
188195
}
@@ -210,6 +217,7 @@ fn generic_extension<'cx>(
210217
arg: TokenStream,
211218
lhses: &[mbe::TokenTree],
212219
rhses: &[mbe::TokenTree],
220+
is_local: bool,
213221
) -> Box<dyn MacResult + 'cx> {
214222
let sess = &cx.sess.parse_sess;
215223

@@ -311,6 +319,7 @@ fn generic_extension<'cx>(
311319
lint_node_id: cx.current_expansion.lint_node_id,
312320
is_trailing_mac: cx.current_expansion.is_trailing_mac,
313321
arm_span,
322+
is_local,
314323
});
315324
}
316325
Failure(token, msg) => match best_failure {
@@ -544,6 +553,9 @@ pub fn compile_declarative_macro(
544553
lhses,
545554
rhses,
546555
valid,
556+
// Macros defined in the current crate have a real node id,
557+
// whereas macros from an external crate have a dummy id.
558+
is_local: def.id != DUMMY_NODE_ID,
547559
}))
548560
}
549561

compiler/rustc_lexer/src/unescape.rs

+30-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::str::Chars;
77
#[cfg(test)]
88
mod tests;
99

10-
/// Errors that can occur during string unescaping.
10+
/// Errors and warnings that can occur during string unescaping.
1111
#[derive(Debug, PartialEq, Eq)]
1212
pub enum EscapeError {
1313
/// Expected 1 char, but 0 were found.
@@ -56,6 +56,20 @@ pub enum EscapeError {
5656
NonAsciiCharInByte,
5757
/// Non-ascii character in byte string literal.
5858
NonAsciiCharInByteString,
59+
60+
/// After a line ending with '\', the next line contains whitespace
61+
/// characters that are not skipped.
62+
UnskippedWhitespaceWarning,
63+
}
64+
65+
impl EscapeError {
66+
/// Returns true for actual errors, as opposed to warnings.
67+
pub fn is_fatal(&self) -> bool {
68+
match self {
69+
EscapeError::UnskippedWhitespaceWarning => false,
70+
_ => true,
71+
}
72+
}
5973
}
6074

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

300-
fn skip_ascii_whitespace(chars: &mut Chars<'_>) {
314+
fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut F)
315+
where
316+
F: FnMut(Range<usize>, Result<char, EscapeError>),
317+
{
301318
let str = chars.as_str();
302319
let first_non_space = str
303320
.bytes()
304321
.position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
305322
.unwrap_or(str.len());
306-
*chars = str[first_non_space..].chars()
323+
let tail = &str[first_non_space..];
324+
if let Some(c) = tail.chars().nth(0) {
325+
// For error reporting, we would like the span to contain the character that was not
326+
// skipped. The +1 is necessary to account for the leading \ that started the escape.
327+
let end = start + first_non_space + c.len_utf8() + 1;
328+
if c.is_whitespace() {
329+
callback(start..end, Err(EscapeError::UnskippedWhitespaceWarning));
330+
}
331+
}
332+
*chars = tail.chars();
307333
}
308334
}
309335

compiler/rustc_lexer/src/unescape/tests.rs

+19
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,25 @@ fn test_unescape_char_good() {
9898
check(r"\u{1F63b}", '😻');
9999
}
100100

101+
#[test]
102+
fn test_unescape_str_warn() {
103+
fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)]) {
104+
let mut unescaped = Vec::with_capacity(literal.len());
105+
unescape_literal(literal, Mode::Str, &mut |range, res| unescaped.push((range, res)));
106+
assert_eq!(unescaped, expected);
107+
}
108+
109+
check(
110+
"\\\n \u{a0} x",
111+
&[
112+
(0..5, Err(EscapeError::UnskippedWhitespaceWarning)),
113+
(3..5, Ok('\u{a0}')),
114+
(5..6, Ok(' ')),
115+
(6..7, Ok('x')),
116+
],
117+
);
118+
}
119+
101120
#[test]
102121
fn test_unescape_str_good() {
103122
fn check(literal_text: &str, expected: &str) {

compiler/rustc_lint_defs/src/builtin.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2799,7 +2799,7 @@ declare_lint! {
27992799
/// [issue #79813]: https://github.com/rust-lang/rust/issues/79813
28002800
/// [future-incompatible]: ../index.md#future-incompatible-lints
28012801
pub SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
2802-
Allow,
2802+
Warn,
28032803
"trailing semicolon in macro body used as expression",
28042804
@future_incompatible = FutureIncompatibleInfo {
28052805
reference: "issue #79813 <https://github.com/rust-lang/rust/issues/79813>",

compiler/rustc_llvm/build.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ fn main() {
182182
} else if target.contains("windows-gnu") {
183183
println!("cargo:rustc-link-lib=shell32");
184184
println!("cargo:rustc-link-lib=uuid");
185-
} else if target.contains("netbsd") || target.contains("haiku") {
185+
} else if target.contains("netbsd") || target.contains("haiku") || target.contains("darwin") {
186186
println!("cargo:rustc-link-lib=z");
187187
}
188188
cmd.args(&components);

compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs

+39-30
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
22
use rustc_middle::mir::*;
33
use rustc_middle::ty;
44
use rustc_span::source_map::DesugaringKind;
5-
use rustc_span::{sym, Span};
5+
use rustc_span::{sym, Span, DUMMY_SP};
6+
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
67

78
use crate::borrow_check::diagnostics::UseSpans;
89
use crate::borrow_check::prefixes::PrefixSet;
@@ -384,36 +385,44 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
384385
}
385386
}
386387
};
387-
if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) {
388-
let def_id = match *move_place.ty(self.body, self.infcx.tcx).ty.kind() {
389-
ty::Adt(self_def, _) => self_def.did,
390-
ty::Foreign(def_id)
391-
| ty::FnDef(def_id, _)
392-
| ty::Closure(def_id, _)
393-
| ty::Generator(def_id, ..)
394-
| ty::Opaque(def_id, _) => def_id,
395-
_ => return err,
388+
let ty = move_place.ty(self.body, self.infcx.tcx).ty;
389+
let def_id = match *ty.kind() {
390+
ty::Adt(self_def, _) => self_def.did,
391+
ty::Foreign(def_id)
392+
| ty::FnDef(def_id, _)
393+
| ty::Closure(def_id, _)
394+
| ty::Generator(def_id, ..)
395+
| ty::Opaque(def_id, _) => def_id,
396+
_ => return err,
397+
};
398+
let is_option = self.infcx.tcx.is_diagnostic_item(sym::option_type, def_id);
399+
let is_result = self.infcx.tcx.is_diagnostic_item(sym::result_type, def_id);
400+
if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
401+
err.span_suggestion_verbose(
402+
span.shrink_to_hi(),
403+
&format!(
404+
"consider borrowing the `{}`'s content",
405+
if is_option { "Option" } else { "Result" }
406+
),
407+
".as_ref()".to_string(),
408+
Applicability::MaybeIncorrect,
409+
);
410+
} else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) {
411+
let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
412+
Some(def_id) => type_known_to_meet_bound_modulo_regions(
413+
&self.infcx,
414+
self.param_env,
415+
self.infcx.tcx.mk_imm_ref(self.infcx.tcx.lifetimes.re_erased, ty),
416+
def_id,
417+
DUMMY_SP,
418+
),
419+
_ => false,
396420
};
397-
let is_option = self.infcx.tcx.is_diagnostic_item(sym::option_type, def_id);
398-
let is_result = self.infcx.tcx.is_diagnostic_item(sym::result_type, def_id);
399-
if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
400-
err.span_suggestion(
401-
span,
402-
&format!(
403-
"consider borrowing the `{}`'s content",
404-
if is_option { "Option" } else { "Result" }
405-
),
406-
format!("{}.as_ref()", snippet),
407-
Applicability::MaybeIncorrect,
408-
);
409-
} else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_)))
410-
&& self.infcx.tcx.is_diagnostic_item(sym::vec_type, def_id)
411-
{
412-
// FIXME: suggest for anything that implements `IntoIterator`.
413-
err.span_suggestion(
414-
span,
415-
"consider iterating over a slice of the `Vec<_>`'s content",
416-
format!("&{}", snippet),
421+
if suggest {
422+
err.span_suggestion_verbose(
423+
span.shrink_to_lo(),
424+
&format!("consider iterating over a slice of the `{}`'s content", ty),
425+
"&".to_string(),
417426
Applicability::MaybeIncorrect,
418427
);
419428
}

compiler/rustc_parse/src/lexer/unescape_error_reporting.rs

+6
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,12 @@ pub(crate) fn emit_unescape_error(
253253
let msg = "invalid trailing slash in literal";
254254
handler.struct_span_err(span, msg).span_label(span, msg).emit();
255255
}
256+
EscapeError::UnskippedWhitespaceWarning => {
257+
let (c, char_span) = last_char();
258+
let msg =
259+
format!("non-ASCII whitespace symbol '{}' is not skipped", c.escape_unicode());
260+
handler.struct_span_warn(span, &msg).span_label(char_span, &msg).emit();
261+
}
256262
}
257263
}
258264

compiler/rustc_typeck/src/check/method/prelude2021.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_ast::Mutability;
55
use rustc_errors::Applicability;
66
use rustc_hir as hir;
77
use rustc_middle::ty::subst::InternalSubsts;
8-
use rustc_middle::ty::{Ref, Ty};
8+
use rustc_middle::ty::{Adt, Ref, Ty};
99
use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
1010
use rustc_span::symbol::kw::Underscore;
1111
use rustc_span::symbol::{sym, Ident};
@@ -255,16 +255,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
255255
method_name.name
256256
));
257257

258-
let self_ty = self
258+
let self_ty_name = self
259259
.sess()
260260
.source_map()
261261
.span_to_snippet(self_ty_span)
262262
.unwrap_or_else(|_| self_ty.to_string());
263263

264+
let self_ty_generics_count = match self_ty.kind() {
265+
// Get the number of generics the self type has (if an Adt) unless we can determine that
266+
// the user has written the self type with generics already which we (naively) do by looking
267+
// for a "<" in `self_ty_name`.
268+
Adt(def, _) if !self_ty_name.contains("<") => self.tcx.generics_of(def.did).count(),
269+
_ => 0,
270+
};
271+
let self_ty_generics = if self_ty_generics_count > 0 {
272+
format!("<{}>", vec!["_"; self_ty_generics_count].join(", "))
273+
} else {
274+
String::new()
275+
};
264276
lint.span_suggestion(
265277
span,
266278
"disambiguate the associated function",
267-
format!("<{} as {}>::{}", self_ty, trait_name, method_name.name,),
279+
format!(
280+
"<{}{} as {}>::{}",
281+
self_ty_name, self_ty_generics, trait_name, method_name.name,
282+
),
268283
Applicability::MachineApplicable,
269284
);
270285

0 commit comments

Comments
 (0)