authorbors <bors@rust-lang.org> 2026-05-27 08:25:14 UTC
committerbors <bors@rust-lang.org> 2026-05-27 08:25:14 UTC
logddc1a64229890506f57bae5b270f9e5f604294ec
treeb6dfb5034184991a20758937dcdade30651044be
parent2cfb951a24de2520de67f6911fd1fc0045a2662e
parenta64a3f207521980f69381c2c0511ae913d702efe

Auto merge of #157005 - JonathanBrouwer:rollup-1BZFgyy, r=JonathanBrouwer

Rollup of 9 pull requests Successful merges: - rust-lang/rust#156796 (Fix missing suggestion when matching `String` with `&str`) - rust-lang/rust#156933 (rustc_parse_format: improve the error diagnostic for `+` sign flag) - rust-lang/rust#156545 (fix issue-144595) - rust-lang/rust#156814 (Extend macOS deployment target mismatch filter to cover dylib and new ld formats) - rust-lang/rust#156851 (rustdoc: avoid ICE when rendering body-less type consts) - rust-lang/rust#156942 (Remove unneeded `#[skip_arg]` attributes) - rust-lang/rust#156972 (add field_projections fixme) - rust-lang/rust#156975 (Move check_cfg out of diagnostic attr module) - rust-lang/rust#156989 (Add missing --set rust.codegen-backends=["gcc"] in the gcc codegen Dockerfile for the core tests)

30 files changed, 753 insertions(+), 479 deletions(-)

compiler/rustc_attr_parsing/src/attributes/cfg.rs+1-2
......@@ -20,7 +20,6 @@ use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
2020use thin_vec::ThinVec;
2121
2222use crate::attributes::AttributeSafety;
23use crate::attributes::diagnostic::check_cfg;
2423use crate::context::{AcceptContext, ShouldEmit};
2524use crate::parser::{
2625 AllowExprMetavar, ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser,
......@@ -29,7 +28,7 @@ use crate::session_diagnostics::{
2928 AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg,
3029 ParsedDescription,
3130};
32use crate::{AttributeParser, parse_version, session_diagnostics};
31use crate::{AttributeParser, check_cfg, parse_version, session_diagnostics};
3332
3433pub const CFG_TEMPLATE: AttributeTemplate = template!(
3534 List: &["predicate"],
compiler/rustc_attr_parsing/src/attributes/diagnostic/check_cfg.rs deleted-444
......@@ -1,444 +0,0 @@
1use rustc_session::Session;
2use rustc_session::config::ExpectedValues;
3use rustc_span::def_id::LOCAL_CRATE;
4use rustc_span::edit_distance::find_best_match_for_name;
5use rustc_span::{ExpnKind, Ident, Span, Symbol, sym};
6
7use crate::errors;
8
9const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35;
10
11enum FilterWellKnownNames {
12 Yes,
13 No,
14}
15
16fn sort_and_truncate_possibilities(
17 sess: &Session,
18 mut possibilities: Vec<Symbol>,
19 filter_well_known_names: FilterWellKnownNames,
20) -> (Vec<Symbol>, usize) {
21 let possibilities_len = possibilities.len();
22
23 let n_possibilities = if sess.opts.unstable_opts.check_cfg_all_expected {
24 possibilities.len()
25 } else {
26 match filter_well_known_names {
27 FilterWellKnownNames::Yes => {
28 possibilities
29 .retain(|cfg_name| !sess.check_config.well_known_names.contains(cfg_name));
30 }
31 FilterWellKnownNames::No => {}
32 };
33 std::cmp::min(possibilities.len(), MAX_CHECK_CFG_NAMES_OR_VALUES)
34 };
35
36 possibilities.sort_by(|s1, s2| s1.as_str().cmp(s2.as_str()));
37
38 let and_more = possibilities_len.saturating_sub(n_possibilities);
39 possibilities.truncate(n_possibilities);
40 (possibilities, and_more)
41}
42
43enum EscapeQuotes {
44 Yes,
45 No,
46}
47
48fn to_check_cfg_arg(name: Ident, value: Option<Symbol>, quotes: EscapeQuotes) -> String {
49 if let Some(value) = value {
50 let value = str::escape_debug(value.as_str()).to_string();
51 let values = match quotes {
52 EscapeQuotes::Yes => format!("\\\"{}\\\"", value.replace("\"", "\\\\\\\\\"")),
53 EscapeQuotes::No => format!("\"{value}\""),
54 };
55 format!("cfg({name}, values({values}))")
56 } else {
57 format!("cfg({name})")
58 }
59}
60
61fn cargo_help_sub(
62 sess: &Session,
63 inst: &impl Fn(EscapeQuotes) -> String,
64) -> errors::UnexpectedCfgCargoHelp {
65 // We don't want to suggest the `build.rs` way to expected cfgs if we are already in a
66 // `build.rs`. We therefor do a best effort check (looking if the `--crate-name` is
67 // `build_script_build`) to try to figure out if we are building a Cargo build script
68
69 let unescaped = &inst(EscapeQuotes::No);
70 if let Some("build_script_build") = sess.opts.crate_name.as_deref() {
71 errors::UnexpectedCfgCargoHelp::lint_cfg(unescaped)
72 } else {
73 errors::UnexpectedCfgCargoHelp::lint_cfg_and_build_rs(unescaped, &inst(EscapeQuotes::Yes))
74 }
75}
76
77fn rustc_macro_help(span: Span) -> Option<errors::UnexpectedCfgRustcMacroHelp> {
78 let oexpn = span.ctxt().outer_expn_data();
79 if let Some(def_id) = oexpn.macro_def_id
80 && let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind
81 && def_id.krate != LOCAL_CRATE
82 {
83 Some(errors::UnexpectedCfgRustcMacroHelp { macro_kind: macro_kind.descr(), macro_name })
84 } else {
85 None
86 }
87}
88
89fn cargo_macro_help(span: Span) -> Option<errors::UnexpectedCfgCargoMacroHelp> {
90 let oexpn = span.ctxt().outer_expn_data();
91 if let Some(def_id) = oexpn.macro_def_id
92 && def_id.krate != LOCAL_CRATE
93 && let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind
94 {
95 Some(errors::UnexpectedCfgCargoMacroHelp { macro_kind: macro_kind.descr(), macro_name })
96 } else {
97 None
98 }
99}
100
101pub(crate) fn unexpected_cfg_name(
102 sess: &Session,
103 (name, name_span): (Symbol, Span),
104 value: Option<(Symbol, Span)>,
105) -> errors::UnexpectedCfgName {
106 #[allow(rustc::potential_query_instability)]
107 let possibilities: Vec<Symbol> = sess.check_config.expecteds.keys().copied().collect();
108
109 let mut names_possibilities: Vec<_> = if value.is_none() {
110 // We later sort and display all the possibilities, so the order here does not matter.
111 #[allow(rustc::potential_query_instability)]
112 sess.check_config
113 .expecteds
114 .iter()
115 .filter_map(|(k, v)| match v {
116 ExpectedValues::Some(v) if v.contains(&Some(name)) => Some(k),
117 _ => None,
118 })
119 .collect()
120 } else {
121 Vec::new()
122 };
123
124 let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
125 let is_from_external_macro = name_span.in_external_macro(sess.source_map());
126 let mut is_feature_cfg = name == sym::feature;
127
128 fn miscapitalized_boolean(name: Symbol) -> Option<bool> {
129 if name.as_str().eq_ignore_ascii_case("false") {
130 Some(false)
131 } else if name.as_str().eq_ignore_ascii_case("true") {
132 Some(true)
133 } else {
134 None
135 }
136 }
137
138 let code_sugg = if is_feature_cfg && is_from_cargo {
139 errors::unexpected_cfg_name::CodeSuggestion::DefineFeatures
140 // Suggest correct `version("..")` predicate syntax
141 } else if let Some((_value, value_span)) = value
142 && name == sym::version
143 {
144 errors::unexpected_cfg_name::CodeSuggestion::VersionSyntax {
145 between_name_and_value: name_span.between(value_span),
146 after_value: value_span.shrink_to_hi(),
147 }
148 // Suggest a literal `false` instead
149 // Detect miscapitalized `False`/`FALSE` etc, ensuring that this isn't `r#false`
150 } else if value.is_none()
151 // If this is a miscapitalized False/FALSE, suggest the boolean literal instead
152 && let Some(boolean) = miscapitalized_boolean(name)
153 // Check this isn't a raw identifier
154 && sess
155 .source_map()
156 .span_to_snippet(name_span)
157 .map_or(true, |snippet| !snippet.contains("r#"))
158 {
159 errors::unexpected_cfg_name::CodeSuggestion::BooleanLiteral {
160 span: name_span,
161 literal: boolean,
162 }
163 // Suggest the most probable if we found one
164 } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
165 is_feature_cfg |= best_match == sym::feature;
166
167 if let Some(ExpectedValues::Some(best_match_values)) =
168 sess.check_config.expecteds.get(&best_match)
169 {
170 // We will soon sort, so the initial order does not matter.
171 #[allow(rustc::potential_query_instability)]
172 let mut possibilities = best_match_values.iter().flatten().collect::<Vec<_>>();
173 possibilities.sort_by_key(|s| s.as_str());
174
175 let get_possibilities_sub = || {
176 if !possibilities.is_empty() {
177 let possibilities =
178 possibilities.iter().copied().cloned().collect::<Vec<_>>().into();
179 Some(errors::unexpected_cfg_name::ExpectedValues { best_match, possibilities })
180 } else {
181 None
182 }
183 };
184
185 let best_match = Ident::new(best_match, name_span);
186 if let Some((value, value_span)) = value {
187 if best_match_values.contains(&Some(value)) {
188 errors::unexpected_cfg_name::CodeSuggestion::SimilarNameAndValue {
189 span: name_span,
190 code: best_match.to_string(),
191 }
192 } else if best_match_values.contains(&None) {
193 errors::unexpected_cfg_name::CodeSuggestion::SimilarNameNoValue {
194 span: name_span.to(value_span),
195 code: best_match.to_string(),
196 }
197 } else if let Some(first_value) = possibilities.first() {
198 errors::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
199 span: name_span.to(value_span),
200 code: format!("{best_match} = \"{first_value}\""),
201 expected: get_possibilities_sub(),
202 }
203 } else {
204 errors::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
205 span: name_span.to(value_span),
206 code: best_match.to_string(),
207 expected: get_possibilities_sub(),
208 }
209 }
210 } else {
211 errors::unexpected_cfg_name::CodeSuggestion::SimilarName {
212 span: name_span,
213 code: best_match.to_string(),
214 expected: get_possibilities_sub(),
215 }
216 }
217 } else {
218 errors::unexpected_cfg_name::CodeSuggestion::SimilarName {
219 span: name_span,
220 code: best_match.to_string(),
221 expected: None,
222 }
223 }
224 } else {
225 let similar_values = if !names_possibilities.is_empty() && names_possibilities.len() <= 3 {
226 names_possibilities.sort();
227 names_possibilities
228 .iter()
229 .map(|cfg_name| errors::unexpected_cfg_name::FoundWithSimilarValue {
230 span: name_span,
231 code: format!("{cfg_name} = \"{name}\""),
232 })
233 .collect()
234 } else {
235 vec![]
236 };
237
238 let (possibilities, and_more) =
239 sort_and_truncate_possibilities(sess, possibilities, FilterWellKnownNames::Yes);
240 let expected_names = if !possibilities.is_empty() {
241 let possibilities: Vec<_> =
242 possibilities.into_iter().map(|s| Ident::new(s, name_span)).collect();
243 Some(errors::unexpected_cfg_name::ExpectedNames {
244 possibilities: possibilities.into(),
245 and_more,
246 })
247 } else {
248 None
249 };
250 errors::unexpected_cfg_name::CodeSuggestion::SimilarValues {
251 with_similar_values: similar_values,
252 expected_names,
253 }
254 };
255
256 let inst = |escape_quotes| {
257 to_check_cfg_arg(Ident::new(name, name_span), value.map(|(v, _s)| v), escape_quotes)
258 };
259
260 let invocation_help = if is_from_cargo {
261 let help = if !is_feature_cfg && !is_from_external_macro {
262 Some(cargo_help_sub(sess, &inst))
263 } else {
264 None
265 };
266 errors::unexpected_cfg_name::InvocationHelp::Cargo {
267 help,
268 macro_help: cargo_macro_help(name_span),
269 }
270 } else {
271 let help = errors::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No));
272 errors::unexpected_cfg_name::InvocationHelp::Rustc {
273 help,
274 macro_help: rustc_macro_help(name_span),
275 }
276 };
277
278 errors::UnexpectedCfgName { code_sugg, invocation_help, name }
279}
280
281pub(crate) fn unexpected_cfg_value(
282 sess: &Session,
283 (name, name_span): (Symbol, Span),
284 value: Option<(Symbol, Span)>,
285) -> errors::UnexpectedCfgValue {
286 let Some(ExpectedValues::Some(values)) = &sess.check_config.expecteds.get(&name) else {
287 panic!(
288 "it shouldn't be possible to have a diagnostic on a value whose name is not in values"
289 );
290 };
291 let mut have_none_possibility = false;
292 // We later sort possibilities if it is not empty, so the
293 // order here does not matter.
294 #[allow(rustc::potential_query_instability)]
295 let possibilities: Vec<Symbol> = values
296 .iter()
297 .inspect(|a| have_none_possibility |= a.is_none())
298 .copied()
299 .flatten()
300 .collect();
301
302 let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
303 let is_from_external_macro = name_span.in_external_macro(sess.source_map());
304
305 let code_sugg = if let Some((value, _)) = value
306 && sess.check_config.well_known_names.contains(&name)
307 && let valid_names = possible_well_known_names_for_cfg_value(sess, value)
308 && !valid_names.is_empty()
309 {
310 // Suggest changing the name to something for which `value` is an expected value.
311 let max_suggestions = 3;
312 let suggestions = valid_names
313 .iter()
314 .take(max_suggestions)
315 .copied()
316 .map(|name| errors::unexpected_cfg_value::ChangeNameSuggestion {
317 span: name_span,
318 name,
319 value,
320 })
321 .collect::<Vec<_>>();
322 errors::unexpected_cfg_value::CodeSuggestion::ChangeName { suggestions }
323 } else if !possibilities.is_empty() {
324 // Show the full list if all possible values for a given name, but don't do it
325 // for names as the possibilities could be very long
326 let expected_values = {
327 let (possibilities, and_more) = sort_and_truncate_possibilities(
328 sess,
329 possibilities.clone(),
330 FilterWellKnownNames::No,
331 );
332 errors::unexpected_cfg_value::ExpectedValues {
333 name,
334 have_none_possibility,
335 possibilities: possibilities.into(),
336 and_more,
337 }
338 };
339
340 let suggestion = if let Some((value, value_span)) = value {
341 // Suggest the most probable if we found one
342 if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
343 Some(errors::unexpected_cfg_value::ChangeValueSuggestion::SimilarName {
344 span: value_span,
345 best_match,
346 })
347 } else {
348 None
349 }
350 } else if let &[first_possibility] = &possibilities[..] {
351 Some(errors::unexpected_cfg_value::ChangeValueSuggestion::SpecifyValue {
352 span: name_span.shrink_to_hi(),
353 first_possibility,
354 })
355 } else {
356 None
357 };
358
359 errors::unexpected_cfg_value::CodeSuggestion::ChangeValue { expected_values, suggestion }
360 } else if have_none_possibility {
361 let suggestion =
362 value.map(|(_value, value_span)| errors::unexpected_cfg_value::RemoveValueSuggestion {
363 span: name_span.shrink_to_hi().to(value_span),
364 });
365 errors::unexpected_cfg_value::CodeSuggestion::RemoveValue { suggestion, name }
366 } else {
367 let span = if let Some((_value, value_span)) = value {
368 name_span.to(value_span)
369 } else {
370 name_span
371 };
372 let suggestion = errors::unexpected_cfg_value::RemoveConditionSuggestion { span };
373 errors::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name }
374 };
375
376 // We don't want to encourage people to add values to a well-known names, as these are
377 // defined by rustc/Rust itself. Users can still do this if they wish, but should not be
378 // encouraged to do so.
379 let can_suggest_adding_value = !sess.check_config.well_known_names.contains(&name)
380 // Except when working on rustc or the standard library itself, in which case we want to
381 // suggest adding these cfgs to the "normal" place because of bootstrapping reasons. As a
382 // basic heuristic, we use the "cheat" unstable feature enable method and the
383 // non-ui-testing enabled option.
384 || (matches!(sess.unstable_features, rustc_feature::UnstableFeatures::Cheat)
385 && !sess.opts.unstable_opts.ui_testing);
386
387 let inst = |escape_quotes| {
388 to_check_cfg_arg(Ident::new(name, name_span), value.map(|(v, _s)| v), escape_quotes)
389 };
390
391 let invocation_help = if is_from_cargo {
392 let help = if name == sym::feature && !is_from_external_macro {
393 if let Some((value, _value_span)) = value {
394 Some(errors::unexpected_cfg_value::CargoHelp::AddFeature { value })
395 } else {
396 Some(errors::unexpected_cfg_value::CargoHelp::DefineFeatures)
397 }
398 } else if can_suggest_adding_value && !is_from_external_macro {
399 Some(errors::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst)))
400 } else {
401 None
402 };
403 errors::unexpected_cfg_value::InvocationHelp::Cargo {
404 help,
405 macro_help: cargo_macro_help(name_span),
406 }
407 } else {
408 let help = if can_suggest_adding_value {
409 Some(errors::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)))
410 } else {
411 None
412 };
413 errors::unexpected_cfg_value::InvocationHelp::Rustc {
414 help,
415 macro_help: rustc_macro_help(name_span),
416 }
417 };
418
419 errors::UnexpectedCfgValue {
420 code_sugg,
421 invocation_help,
422 has_value: value.is_some(),
423 value: value.map_or_else(String::new, |(v, _span)| v.to_string()),
424 }
425}
426
427fn possible_well_known_names_for_cfg_value(sess: &Session, value: Symbol) -> Vec<Symbol> {
428 #[allow(rustc::potential_query_instability)]
429 let mut names = sess
430 .check_config
431 .well_known_names
432 .iter()
433 .filter(|name| {
434 sess.check_config
435 .expecteds
436 .get(*name)
437 .map(|expected_values| expected_values.contains(&Some(value)))
438 .unwrap_or_default()
439 })
440 .copied()
441 .collect::<Vec<_>>();
442 names.sort_by(|a, b| a.as_str().cmp(b.as_str()));
443 names
444}
compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs-1
......@@ -23,7 +23,6 @@ use crate::errors::{
2323};
2424use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser};
2525
26pub(crate) mod check_cfg;
2726pub(crate) mod do_not_recommend;
2827pub(crate) mod on_const;
2928pub(crate) mod on_move;
compiler/rustc_attr_parsing/src/check_cfg.rs created+444
......@@ -0,0 +1,444 @@
1use rustc_session::Session;
2use rustc_session::config::ExpectedValues;
3use rustc_span::def_id::LOCAL_CRATE;
4use rustc_span::edit_distance::find_best_match_for_name;
5use rustc_span::{ExpnKind, Ident, Span, Symbol, sym};
6
7use crate::errors;
8
9const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35;
10
11enum FilterWellKnownNames {
12 Yes,
13 No,
14}
15
16fn sort_and_truncate_possibilities(
17 sess: &Session,
18 mut possibilities: Vec<Symbol>,
19 filter_well_known_names: FilterWellKnownNames,
20) -> (Vec<Symbol>, usize) {
21 let possibilities_len = possibilities.len();
22
23 let n_possibilities = if sess.opts.unstable_opts.check_cfg_all_expected {
24 possibilities.len()
25 } else {
26 match filter_well_known_names {
27 FilterWellKnownNames::Yes => {
28 possibilities
29 .retain(|cfg_name| !sess.check_config.well_known_names.contains(cfg_name));
30 }
31 FilterWellKnownNames::No => {}
32 };
33 std::cmp::min(possibilities.len(), MAX_CHECK_CFG_NAMES_OR_VALUES)
34 };
35
36 possibilities.sort_by(|s1, s2| s1.as_str().cmp(s2.as_str()));
37
38 let and_more = possibilities_len.saturating_sub(n_possibilities);
39 possibilities.truncate(n_possibilities);
40 (possibilities, and_more)
41}
42
43enum EscapeQuotes {
44 Yes,
45 No,
46}
47
48fn to_check_cfg_arg(name: Ident, value: Option<Symbol>, quotes: EscapeQuotes) -> String {
49 if let Some(value) = value {
50 let value = str::escape_debug(value.as_str()).to_string();
51 let values = match quotes {
52 EscapeQuotes::Yes => format!("\\\"{}\\\"", value.replace("\"", "\\\\\\\\\"")),
53 EscapeQuotes::No => format!("\"{value}\""),
54 };
55 format!("cfg({name}, values({values}))")
56 } else {
57 format!("cfg({name})")
58 }
59}
60
61fn cargo_help_sub(
62 sess: &Session,
63 inst: &impl Fn(EscapeQuotes) -> String,
64) -> errors::UnexpectedCfgCargoHelp {
65 // We don't want to suggest the `build.rs` way to expected cfgs if we are already in a
66 // `build.rs`. We therefor do a best effort check (looking if the `--crate-name` is
67 // `build_script_build`) to try to figure out if we are building a Cargo build script
68
69 let unescaped = &inst(EscapeQuotes::No);
70 if let Some("build_script_build") = sess.opts.crate_name.as_deref() {
71 errors::UnexpectedCfgCargoHelp::lint_cfg(unescaped)
72 } else {
73 errors::UnexpectedCfgCargoHelp::lint_cfg_and_build_rs(unescaped, &inst(EscapeQuotes::Yes))
74 }
75}
76
77fn rustc_macro_help(span: Span) -> Option<errors::UnexpectedCfgRustcMacroHelp> {
78 let oexpn = span.ctxt().outer_expn_data();
79 if let Some(def_id) = oexpn.macro_def_id
80 && let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind
81 && def_id.krate != LOCAL_CRATE
82 {
83 Some(errors::UnexpectedCfgRustcMacroHelp { macro_kind: macro_kind.descr(), macro_name })
84 } else {
85 None
86 }
87}
88
89fn cargo_macro_help(span: Span) -> Option<errors::UnexpectedCfgCargoMacroHelp> {
90 let oexpn = span.ctxt().outer_expn_data();
91 if let Some(def_id) = oexpn.macro_def_id
92 && def_id.krate != LOCAL_CRATE
93 && let ExpnKind::Macro(macro_kind, macro_name) = oexpn.kind
94 {
95 Some(errors::UnexpectedCfgCargoMacroHelp { macro_kind: macro_kind.descr(), macro_name })
96 } else {
97 None
98 }
99}
100
101pub(crate) fn unexpected_cfg_name(
102 sess: &Session,
103 (name, name_span): (Symbol, Span),
104 value: Option<(Symbol, Span)>,
105) -> errors::UnexpectedCfgName {
106 #[allow(rustc::potential_query_instability)]
107 let possibilities: Vec<Symbol> = sess.check_config.expecteds.keys().copied().collect();
108
109 let mut names_possibilities: Vec<_> = if value.is_none() {
110 // We later sort and display all the possibilities, so the order here does not matter.
111 #[allow(rustc::potential_query_instability)]
112 sess.check_config
113 .expecteds
114 .iter()
115 .filter_map(|(k, v)| match v {
116 ExpectedValues::Some(v) if v.contains(&Some(name)) => Some(k),
117 _ => None,
118 })
119 .collect()
120 } else {
121 Vec::new()
122 };
123
124 let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
125 let is_from_external_macro = name_span.in_external_macro(sess.source_map());
126 let mut is_feature_cfg = name == sym::feature;
127
128 fn miscapitalized_boolean(name: Symbol) -> Option<bool> {
129 if name.as_str().eq_ignore_ascii_case("false") {
130 Some(false)
131 } else if name.as_str().eq_ignore_ascii_case("true") {
132 Some(true)
133 } else {
134 None
135 }
136 }
137
138 let code_sugg = if is_feature_cfg && is_from_cargo {
139 errors::unexpected_cfg_name::CodeSuggestion::DefineFeatures
140 // Suggest correct `version("..")` predicate syntax
141 } else if let Some((_value, value_span)) = value
142 && name == sym::version
143 {
144 errors::unexpected_cfg_name::CodeSuggestion::VersionSyntax {
145 between_name_and_value: name_span.between(value_span),
146 after_value: value_span.shrink_to_hi(),
147 }
148 // Suggest a literal `false` instead
149 // Detect miscapitalized `False`/`FALSE` etc, ensuring that this isn't `r#false`
150 } else if value.is_none()
151 // If this is a miscapitalized False/FALSE, suggest the boolean literal instead
152 && let Some(boolean) = miscapitalized_boolean(name)
153 // Check this isn't a raw identifier
154 && sess
155 .source_map()
156 .span_to_snippet(name_span)
157 .map_or(true, |snippet| !snippet.contains("r#"))
158 {
159 errors::unexpected_cfg_name::CodeSuggestion::BooleanLiteral {
160 span: name_span,
161 literal: boolean,
162 }
163 // Suggest the most probable if we found one
164 } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
165 is_feature_cfg |= best_match == sym::feature;
166
167 if let Some(ExpectedValues::Some(best_match_values)) =
168 sess.check_config.expecteds.get(&best_match)
169 {
170 // We will soon sort, so the initial order does not matter.
171 #[allow(rustc::potential_query_instability)]
172 let mut possibilities = best_match_values.iter().flatten().collect::<Vec<_>>();
173 possibilities.sort_by_key(|s| s.as_str());
174
175 let get_possibilities_sub = || {
176 if !possibilities.is_empty() {
177 let possibilities =
178 possibilities.iter().copied().cloned().collect::<Vec<_>>().into();
179 Some(errors::unexpected_cfg_name::ExpectedValues { best_match, possibilities })
180 } else {
181 None
182 }
183 };
184
185 let best_match = Ident::new(best_match, name_span);
186 if let Some((value, value_span)) = value {
187 if best_match_values.contains(&Some(value)) {
188 errors::unexpected_cfg_name::CodeSuggestion::SimilarNameAndValue {
189 span: name_span,
190 code: best_match.to_string(),
191 }
192 } else if best_match_values.contains(&None) {
193 errors::unexpected_cfg_name::CodeSuggestion::SimilarNameNoValue {
194 span: name_span.to(value_span),
195 code: best_match.to_string(),
196 }
197 } else if let Some(first_value) = possibilities.first() {
198 errors::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
199 span: name_span.to(value_span),
200 code: format!("{best_match} = \"{first_value}\""),
201 expected: get_possibilities_sub(),
202 }
203 } else {
204 errors::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
205 span: name_span.to(value_span),
206 code: best_match.to_string(),
207 expected: get_possibilities_sub(),
208 }
209 }
210 } else {
211 errors::unexpected_cfg_name::CodeSuggestion::SimilarName {
212 span: name_span,
213 code: best_match.to_string(),
214 expected: get_possibilities_sub(),
215 }
216 }
217 } else {
218 errors::unexpected_cfg_name::CodeSuggestion::SimilarName {
219 span: name_span,
220 code: best_match.to_string(),
221 expected: None,
222 }
223 }
224 } else {
225 let similar_values = if !names_possibilities.is_empty() && names_possibilities.len() <= 3 {
226 names_possibilities.sort();
227 names_possibilities
228 .iter()
229 .map(|cfg_name| errors::unexpected_cfg_name::FoundWithSimilarValue {
230 span: name_span,
231 code: format!("{cfg_name} = \"{name}\""),
232 })
233 .collect()
234 } else {
235 vec![]
236 };
237
238 let (possibilities, and_more) =
239 sort_and_truncate_possibilities(sess, possibilities, FilterWellKnownNames::Yes);
240 let expected_names = if !possibilities.is_empty() {
241 let possibilities: Vec<_> =
242 possibilities.into_iter().map(|s| Ident::new(s, name_span)).collect();
243 Some(errors::unexpected_cfg_name::ExpectedNames {
244 possibilities: possibilities.into(),
245 and_more,
246 })
247 } else {
248 None
249 };
250 errors::unexpected_cfg_name::CodeSuggestion::SimilarValues {
251 with_similar_values: similar_values,
252 expected_names,
253 }
254 };
255
256 let inst = |escape_quotes| {
257 to_check_cfg_arg(Ident::new(name, name_span), value.map(|(v, _s)| v), escape_quotes)
258 };
259
260 let invocation_help = if is_from_cargo {
261 let help = if !is_feature_cfg && !is_from_external_macro {
262 Some(cargo_help_sub(sess, &inst))
263 } else {
264 None
265 };
266 errors::unexpected_cfg_name::InvocationHelp::Cargo {
267 help,
268 macro_help: cargo_macro_help(name_span),
269 }
270 } else {
271 let help = errors::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No));
272 errors::unexpected_cfg_name::InvocationHelp::Rustc {
273 help,
274 macro_help: rustc_macro_help(name_span),
275 }
276 };
277
278 errors::UnexpectedCfgName { code_sugg, invocation_help, name }
279}
280
281pub(crate) fn unexpected_cfg_value(
282 sess: &Session,
283 (name, name_span): (Symbol, Span),
284 value: Option<(Symbol, Span)>,
285) -> errors::UnexpectedCfgValue {
286 let Some(ExpectedValues::Some(values)) = &sess.check_config.expecteds.get(&name) else {
287 panic!(
288 "it shouldn't be possible to have a diagnostic on a value whose name is not in values"
289 );
290 };
291 let mut have_none_possibility = false;
292 // We later sort possibilities if it is not empty, so the
293 // order here does not matter.
294 #[allow(rustc::potential_query_instability)]
295 let possibilities: Vec<Symbol> = values
296 .iter()
297 .inspect(|a| have_none_possibility |= a.is_none())
298 .copied()
299 .flatten()
300 .collect();
301
302 let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
303 let is_from_external_macro = name_span.in_external_macro(sess.source_map());
304
305 let code_sugg = if let Some((value, _)) = value
306 && sess.check_config.well_known_names.contains(&name)
307 && let valid_names = possible_well_known_names_for_cfg_value(sess, value)
308 && !valid_names.is_empty()
309 {
310 // Suggest changing the name to something for which `value` is an expected value.
311 let max_suggestions = 3;
312 let suggestions = valid_names
313 .iter()
314 .take(max_suggestions)
315 .copied()
316 .map(|name| errors::unexpected_cfg_value::ChangeNameSuggestion {
317 span: name_span,
318 name,
319 value,
320 })
321 .collect::<Vec<_>>();
322 errors::unexpected_cfg_value::CodeSuggestion::ChangeName { suggestions }
323 } else if !possibilities.is_empty() {
324 // Show the full list if all possible values for a given name, but don't do it
325 // for names as the possibilities could be very long
326 let expected_values = {
327 let (possibilities, and_more) = sort_and_truncate_possibilities(
328 sess,
329 possibilities.clone(),
330 FilterWellKnownNames::No,
331 );
332 errors::unexpected_cfg_value::ExpectedValues {
333 name,
334 have_none_possibility,
335 possibilities: possibilities.into(),
336 and_more,
337 }
338 };
339
340 let suggestion = if let Some((value, value_span)) = value {
341 // Suggest the most probable if we found one
342 if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
343 Some(errors::unexpected_cfg_value::ChangeValueSuggestion::SimilarName {
344 span: value_span,
345 best_match,
346 })
347 } else {
348 None
349 }
350 } else if let &[first_possibility] = &possibilities[..] {
351 Some(errors::unexpected_cfg_value::ChangeValueSuggestion::SpecifyValue {
352 span: name_span.shrink_to_hi(),
353 first_possibility,
354 })
355 } else {
356 None
357 };
358
359 errors::unexpected_cfg_value::CodeSuggestion::ChangeValue { expected_values, suggestion }
360 } else if have_none_possibility {
361 let suggestion =
362 value.map(|(_value, value_span)| errors::unexpected_cfg_value::RemoveValueSuggestion {
363 span: name_span.shrink_to_hi().to(value_span),
364 });
365 errors::unexpected_cfg_value::CodeSuggestion::RemoveValue { suggestion, name }
366 } else {
367 let span = if let Some((_value, value_span)) = value {
368 name_span.to(value_span)
369 } else {
370 name_span
371 };
372 let suggestion = errors::unexpected_cfg_value::RemoveConditionSuggestion { span };
373 errors::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name }
374 };
375
376 // We don't want to encourage people to add values to a well-known names, as these are
377 // defined by rustc/Rust itself. Users can still do this if they wish, but should not be
378 // encouraged to do so.
379 let can_suggest_adding_value = !sess.check_config.well_known_names.contains(&name)
380 // Except when working on rustc or the standard library itself, in which case we want to
381 // suggest adding these cfgs to the "normal" place because of bootstrapping reasons. As a
382 // basic heuristic, we use the "cheat" unstable feature enable method and the
383 // non-ui-testing enabled option.
384 || (matches!(sess.unstable_features, rustc_feature::UnstableFeatures::Cheat)
385 && !sess.opts.unstable_opts.ui_testing);
386
387 let inst = |escape_quotes| {
388 to_check_cfg_arg(Ident::new(name, name_span), value.map(|(v, _s)| v), escape_quotes)
389 };
390
391 let invocation_help = if is_from_cargo {
392 let help = if name == sym::feature && !is_from_external_macro {
393 if let Some((value, _value_span)) = value {
394 Some(errors::unexpected_cfg_value::CargoHelp::AddFeature { value })
395 } else {
396 Some(errors::unexpected_cfg_value::CargoHelp::DefineFeatures)
397 }
398 } else if can_suggest_adding_value && !is_from_external_macro {
399 Some(errors::unexpected_cfg_value::CargoHelp::Other(cargo_help_sub(sess, &inst)))
400 } else {
401 None
402 };
403 errors::unexpected_cfg_value::InvocationHelp::Cargo {
404 help,
405 macro_help: cargo_macro_help(name_span),
406 }
407 } else {
408 let help = if can_suggest_adding_value {
409 Some(errors::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)))
410 } else {
411 None
412 };
413 errors::unexpected_cfg_value::InvocationHelp::Rustc {
414 help,
415 macro_help: rustc_macro_help(name_span),
416 }
417 };
418
419 errors::UnexpectedCfgValue {
420 code_sugg,
421 invocation_help,
422 has_value: value.is_some(),
423 value: value.map_or_else(String::new, |(v, _span)| v.to_string()),
424 }
425}
426
427fn possible_well_known_names_for_cfg_value(sess: &Session, value: Symbol) -> Vec<Symbol> {
428 #[allow(rustc::potential_query_instability)]
429 let mut names = sess
430 .check_config
431 .well_known_names
432 .iter()
433 .filter(|name| {
434 sess.check_config
435 .expecteds
436 .get(*name)
437 .map(|expected_values| expected_values.contains(&Some(value)))
438 .unwrap_or_default()
439 })
440 .copied()
441 .collect::<Vec<_>>();
442 names.sort_by(|a, b| a.as_str().cmp(b.as_str()));
443 names
444}
compiler/rustc_attr_parsing/src/lib.rs+1
......@@ -106,6 +106,7 @@ mod interface;
106106/// like lists or name-value pairs.
107107pub mod parser;
108108
109mod check_cfg;
109110mod early_parsed;
110111mod errors;
111112mod safety;
compiler/rustc_attr_parsing/src/session_diagnostics.rs-8
......@@ -274,11 +274,7 @@ pub(crate) enum IncorrectReprFormatGenericCause {
274274 Int {
275275 #[primary_span]
276276 span: Span,
277
278 #[skip_arg]
279277 name: Symbol,
280
281 #[skip_arg]
282278 value: u128,
283279 },
284280
......@@ -290,11 +286,7 @@ pub(crate) enum IncorrectReprFormatGenericCause {
290286 Symbol {
291287 #[primary_span]
292288 span: Span,
293
294 #[skip_arg]
295289 name: Symbol,
296
297 #[skip_arg]
298290 value: Symbol,
299291 },
300292}
compiler/rustc_codegen_ssa/src/back/link.rs+9-3
......@@ -781,9 +781,15 @@ fn report_linker_output(
781781
782782 // FIXME: Tracked by https://github.com/rust-lang/rust/issues/136113
783783 let deployment_mismatch = |line: &str| {
784 line.starts_with("ld: warning: object file (")
785 && line.contains("was built for newer 'macOS' version")
786 && line.contains("than being linked")
784 // ld64 (object files + dylibs) and ld_prime (object files only):
785 (line.starts_with("ld: ")
786 && line.contains("was built for newer")
787 && line.contains("than being linked"))
788 // ld_prime (Xcode 15+, dylibs only):
789 || (line.starts_with("ld: ")
790 && line.contains("building for")
791 && line.contains("but linking with")
792 && line.contains("which was built for newer version"))
787793 };
788794 // FIXME: This is a real warning we would like to show, but it hits too many crates
789795 // to want to turn it on immediately.
compiler/rustc_hir_typeck/src/pat.rs+16-1
......@@ -1007,7 +1007,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10071007 //
10081008 // then that's equivalent to there existing a LUB.
10091009 let cause = self.pattern_cause(ti, span);
1010 if let Err(err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) {
1010 if let Err(mut err) = self.demand_suptype_with_origin(&cause, expected, pat_ty) {
1011 // If scrutinee is String and pattern is &str, suggest .as_str()
1012 let expected = self.resolve_vars_with_obligations(expected);
1013 if let ty::Adt(adt, _) = expected.kind()
1014 && self.tcx.is_lang_item(adt.did(), LangItem::String)
1015 && pat_ty.is_ref()
1016 && pat_ty.peel_refs().is_str()
1017 && let Some(origin_expr) = ti.origin_expr
1018 {
1019 err.span_suggestion_verbose(
1020 origin_expr.span.shrink_to_hi(),
1021 "consider converting the `String` to a `&str` using `.as_str()`",
1022 ".as_str()",
1023 Applicability::MachineApplicable,
1024 );
1025 }
10111026 err.emit();
10121027 }
10131028
compiler/rustc_next_trait_solver/src/solve/trait_goals.rs+2
......@@ -898,6 +898,8 @@ where
898898 predicate: TraitRef::new(ecx.cx(), sized_trait, [ty]).upcast(ecx.cx()),
899899 },
900900 );
901 // FIXME(field_projections): This function does some questionable incomplete stuff by
902 // returning `Err(NoSolution)` on ambiguity.
901903 ecx.try_evaluate_added_goals()? == Certainty::Yes
902904 }
903905 && match base.kind() {
compiler/rustc_parse/src/errors.rs+25
......@@ -4639,3 +4639,28 @@ pub(crate) struct ReservedMultihashLint {
46394639 )]
46404640 pub suggestion: Span,
46414641}
4642
4643#[derive(Subdiagnostic)]
4644#[suggestion(
4645 "if you meant to write a path, use a double colon:",
4646 code = "::",
4647 applicability = "maybe-incorrect"
4648)]
4649pub(crate) struct UseDoubleColonSuggestion {
4650 #[primary_span]
4651 pub colon: Span,
4652}
4653
4654#[derive(Subdiagnostic)]
4655#[multipart_suggestion(
4656 "if you meant to create a regular struct, use curly braces:",
4657 applicability = "maybe-incorrect"
4658)]
4659pub(crate) struct UseRegularStructSuggestion {
4660 #[suggestion_part(code = "{{")]
4661 pub open: Span,
4662 #[suggestion_part(code = "}}")]
4663 pub close: Span,
4664 #[suggestion_part(code = "")]
4665 pub semicolon: Option<Span>,
4666}
compiler/rustc_parse/src/parser/item.rs+23-4
......@@ -23,7 +23,10 @@ use super::{
2323 AllowConstBlockItems, AttrWrapper, ExpKeywordPair, ExpTokenPair, FollowedByType, ForceCollect,
2424 Parser, PathStyle, Recovered, Trailing, UsePreAttrPos,
2525};
26use crate::errors::{self, FnPointerCannotBeAsync, FnPointerCannotBeConst, MacroExpandsToAdtField};
26use crate::errors::{
27 self, FnPointerCannotBeAsync, FnPointerCannotBeConst, MacroExpandsToAdtField,
28 UseDoubleColonSuggestion, UseRegularStructSuggestion,
29};
2730use crate::exp;
2831
2932impl<'a> Parser<'a> {
......@@ -2084,10 +2087,11 @@ impl<'a> Parser<'a> {
20842087 Safety::Default
20852088 }
20862089 }
2087
2090 /// This is the case where we find `struct Foo<T>(T) where T: Copy;`
2091 /// Unit like structs are handled in parse_item_struct function
20882092 pub(super) fn parse_tuple_struct_body(&mut self) -> PResult<'a, ThinVec<FieldDef>> {
2089 // This is the case where we find `struct Foo<T>(T) where T: Copy;`
2090 // Unit like structs are handled in parse_item_struct function
2093 let openparen_span = self.token.span;
2094 let mut encountered_colon = false;
20912095 self.parse_paren_comma_seq(|p| {
20922096 let attrs = p.parse_outer_attributes()?;
20932097 p.collect_tokens(None, attrs, ForceCollect::No, |p, attrs| {
......@@ -2109,6 +2113,8 @@ impl<'a> Parser<'a> {
21092113 }
21102114 };
21112115 let mut_restriction = p.parse_mut_restriction()?;
2116 encountered_colon |=
2117 p.token.is_ident() && p.look_ahead(1, |tok| tok == &token::Colon);
21122118 // Unsafe fields are not supported in tuple structs, as doing so would result in a
21132119 // parsing ambiguity for `struct X(unsafe fn())`.
21142120 let ty = match p.parse_ty() {
......@@ -2156,6 +2162,19 @@ impl<'a> Parser<'a> {
21562162 })
21572163 })
21582164 .map(|(r, _)| r)
2165 .map_err(|mut error| {
2166 if encountered_colon {
2167 error.subdiagnostic(UseDoubleColonSuggestion { colon: self.token.span });
2168 self.eat_to_tokens(&[exp!(CloseParen)]);
2169 self.bump();
2170 error.subdiagnostic(UseRegularStructSuggestion {
2171 open: openparen_span,
2172 close: self.prev_token.span,
2173 semicolon: if self.token == token::Semi { Some(self.token.span) } else { None },
2174 });
2175 }
2176 error
2177 })
21592178 }
21602179
21612180 /// Parses an element of a struct declaration.
compiler/rustc_parse_format/src/lib.rs+18
......@@ -491,6 +491,7 @@ impl<'input> Parser<'input> {
491491 ('<' | '^' | '>', _) => self.suggest_format_align(c),
492492 (',', _) => self.suggest_unsupported_python_numeric_grouping(),
493493 ('=', '}') => self.suggest_rust_debug_printing_macro(),
494 ('+', _) => self.suggest_format_missing_colon_for_sign(),
494495 _ => self.suggest_positional_arg_instead_of_captured_arg(arg),
495496 }
496497 }
......@@ -939,6 +940,23 @@ impl<'input> Parser<'input> {
939940 }
940941 }
941942
943 fn suggest_format_missing_colon_for_sign(&mut self) {
944 if let Some((range, _)) = self.consume_pos('+') {
945 self.errors.insert(
946 0,
947 ParseError {
948 description: "the `+` sign flag must appear after `:` in a format string"
949 .to_owned(),
950 note: Some("`+` comes after `:`, try `{:+}` instead of `{+}`".to_owned()),
951 label: "expected `:` before `+` sign flag".to_owned(),
952 span: range,
953 secondary_label: None,
954 suggestion: Suggestion::None,
955 },
956 );
957 }
958 }
959
942960 fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: &Argument<'_>) {
943961 // If the argument is not an identifier, it is not a field access.
944962 if !arg.is_identifier() {
compiler/rustc_parse_format/src/tests.rs+10
......@@ -595,3 +595,13 @@ fn diagnostic_format_mod() {
595595 assert_eq!(parser.line_spans, &[]);
596596 assert!(parser.errors.is_empty());
597597}
598#[test]
599fn format_plus_sign_missing_colon_error() {
600 // `{+}` should produce an error suggesting `:` before `+`
601 let mut p = Parser::new("{+}", None, None, false, ParseMode::Format);
602 let _ = p.by_ref().collect::<Vec<Piece<'static>>>();
603 assert!(!p.errors.is_empty());
604 assert!(p.errors[0].description.contains("`+` sign flag must appear after `:`"));
605 assert!(p.errors[0].label.contains("expected `:` before `+` sign flag"));
606 assert_eq!(p.errors[0].span, 2..3);
607}
compiler/rustc_trait_selection/src/errors.rs-9
......@@ -869,7 +869,6 @@ pub(crate) enum ExplicitLifetimeRequired<'a> {
869869 style = "verbose"
870870 )]
871871 new_ty_span: Span,
872 #[skip_arg]
873872 new_ty: Ty<'a>,
874873 },
875874 #[diag("explicit lifetime required in parameter type", code = E0621)]
......@@ -885,7 +884,6 @@ pub(crate) enum ExplicitLifetimeRequired<'a> {
885884 style = "verbose"
886885 )]
887886 new_ty_span: Span,
888 #[skip_arg]
889887 new_ty: Ty<'a>,
890888 },
891889}
......@@ -1519,7 +1517,6 @@ pub(crate) enum FunctionPointerSuggestion<'a> {
15191517 RemoveRef {
15201518 #[primary_span]
15211519 span: Span,
1522 #[skip_arg]
15231520 fn_name: String,
15241521 },
15251522 #[suggestion(
......@@ -1531,9 +1528,7 @@ pub(crate) enum FunctionPointerSuggestion<'a> {
15311528 CastRef {
15321529 #[primary_span]
15331530 span: Span,
1534 #[skip_arg]
15351531 fn_name: String,
1536 #[skip_arg]
15371532 sig: Binder<'a, FnSig<'a>>,
15381533 },
15391534 #[suggestion(
......@@ -1545,7 +1540,6 @@ pub(crate) enum FunctionPointerSuggestion<'a> {
15451540 Cast {
15461541 #[primary_span]
15471542 span: Span,
1548 #[skip_arg]
15491543 sig: Binder<'a, FnSig<'a>>,
15501544 },
15511545 #[suggestion(
......@@ -1557,7 +1551,6 @@ pub(crate) enum FunctionPointerSuggestion<'a> {
15571551 CastBoth {
15581552 #[primary_span]
15591553 span: Span,
1560 #[skip_arg]
15611554 found_sig: Binder<'a, FnSig<'a>>,
15621555 expected_sig: Binder<'a, FnSig<'a>>,
15631556 },
......@@ -1570,9 +1563,7 @@ pub(crate) enum FunctionPointerSuggestion<'a> {
15701563 CastBothRef {
15711564 #[primary_span]
15721565 span: Span,
1573 #[skip_arg]
15741566 fn_name: String,
1575 #[skip_arg]
15761567 found_sig: Binder<'a, FnSig<'a>>,
15771568 expected_sig: Binder<'a, FnSig<'a>>,
15781569 },
src/ci/docker/host-x86_64/x86_64-gnu-gcc-core-tests/Dockerfile+2-1
......@@ -44,4 +44,5 @@ ENV RUST_CONFIGURE_ARGS="--build=x86_64-unknown-linux-gnu \
4444 --set rust.codegen-backends=[\\\"gcc\\\"]"
4545ENV SCRIPT="python3 ../x.py \
4646 --stage 1 \
47 test library/coretests"
47 test library/coretests \
48 --set rust.codegen-backends=[\\\"gcc\\\"]"
src/librustdoc/clean/utils.rs+4-2
......@@ -351,8 +351,10 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
351351pub(crate) fn print_const(tcx: TyCtxt<'_>, n: ty::Const<'_>) -> String {
352352 match n.kind() {
353353 ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args: _ }) => {
354 if let Some(def) = def.as_local() {
355 rendered_const(tcx, tcx.hir_body_owned_by(def), def)
354 if let Some(def) = def.as_local()
355 && let Some(body_id) = tcx.hir_maybe_body_owned_by(def)
356 {
357 rendered_const(tcx, body_id, def)
356358 } else {
357359 inline::print_inlined_const(tcx, def)
358360 }
tests/run-make/macos-deployment-target-warning/dylib_warnings.txt created+11
......@@ -0,0 +1,11 @@
1warning: NORMALIZED_DYLIB_DEPLOYMENT_MISMATCH_LINKER_WARNING
2
3 |
4note: the lint level is defined here
5 --> main_dylib.rs:1:9
6 |
71 | #![warn(linker_info, linker_messages)]
8 | ^^^^^^^^^^^
9
10warning: 1 warning emitted
11
tests/run-make/macos-deployment-target-warning/main_dylib.rs created+8
......@@ -0,0 +1,8 @@
1#![warn(linker_info, linker_messages)]
2unsafe extern "C" {
3 safe fn foo();
4}
5
6fn main() {
7 foo();
8}
tests/run-make/macos-deployment-target-warning/rmake.rs+32-1
......@@ -1,4 +1,6 @@
1// ignore-tidy-linelength
12//! Tests that deployment target linker warnings are shown as `linker-info`, not `linker-messages`
3//! See <https://github.com/rust-lang/rust/issues/156714>
24
35//@ only-macos
46
......@@ -7,6 +9,12 @@ use run_make_support::external_deps::llvm::llvm_ar;
79use run_make_support::{diff, rustc};
810
911fn main() {
12 let ld64_obj = r"ld: warning: object file \(.*\) was built for newer .+ version \(\d+\.\d+\) than being linked \(\d+\.\d+\)";
13 let ld_prime_obj = r"ld: warning: object file \(.*\) was built for newer '.+' version \(\d+\.\d+\) than being linked \(\d+\.\d+\)";
14 let ld64_dylib = r"ld: warning: dylib \(.*\) was built for newer .+ version \(\d+\.\d+\) than being linked \(\d+\.\d+\)";
15 let ld_prime_dylib = r"ld: warning: building for [^ ,]+, but linking with dylib '[^']*' which was built for newer version [0-9.]+";
16
17 // Test 1: static archive (object file mismatch)
1018 cc().arg("-c").arg("-mmacosx-version-min=15.5").output("foo.o").input("foo.c").run();
1119 llvm_ar().obj_to_ar().output_input("libfoo.a", "foo.o").run();
1220
......@@ -21,6 +29,29 @@ fn main() {
2129 diff()
2230 .expected_file("warnings.txt")
2331 .actual_text("(rustc -W linker-info)", &warnings)
24 .normalize(r"\(.*/rmake_out/", "(TEST_DIR/")
32 .normalize(ld64_obj, "NORMALIZED_OBJECT_DEPLOYMENT_MISMATCH_LINKER_WARNING")
33 .normalize(ld_prime_obj, "NORMALIZED_OBJECT_DEPLOYMENT_MISMATCH_LINKER_WARNING")
34 .run();
35
36 // Test 2: shared library (dylib mismatch)
37 cc().arg("-shared")
38 .arg("-mmacosx-version-min=15.5")
39 .output("libbar.dylib")
40 .input("foo.c")
41 .run();
42
43 let dylib_warnings = rustc()
44 .arg("-lbar")
45 .link_arg("-mmacosx-version-min=11.2")
46 .input("main_dylib.rs")
47 .crate_type("bin")
2548 .run()
49 .stderr_utf8();
50
51 diff()
52 .expected_file("dylib_warnings.txt")
53 .actual_text("(rustc -W linker-info dylib)", &dylib_warnings)
54 .normalize(ld64_dylib, "NORMALIZED_DYLIB_DEPLOYMENT_MISMATCH_LINKER_WARNING")
55 .normalize(ld_prime_dylib, "NORMALIZED_DYLIB_DEPLOYMENT_MISMATCH_LINKER_WARNING")
56 .run();
2657}
tests/run-make/macos-deployment-target-warning/warnings.txt+1-1
......@@ -1,4 +1,4 @@
1warning: ld: warning: object file (TEST_DIR/libfoo.a[2](foo.o)) was built for newer 'macOS' version (15.5) than being linked (11.2)
1warning: NORMALIZED_OBJECT_DEPLOYMENT_MISMATCH_LINKER_WARNING
22
33 |
44note: the lint level is defined here
tests/rustdoc-ui/type-const-associated-const-no-body.rs created+16
......@@ -0,0 +1,16 @@
1//! Regression test for <https://github.com/rust-lang/rust/issues/149287>
2//! Ensure that rustdoc does not ICE when a body-less type const is used
3//! as an associated const.
4//@ check-pass
5
6#![feature(min_generic_const_args)]
7
8pub trait Tr {
9 type const SIZE: usize;
10}
11
12fn mk_array<T: Tr>() -> [(); <T as Tr>::SIZE] {
13 [(); T::SIZE]
14}
15
16fn main() {}
tests/ui/fmt/format-string-wrong-order.rs+4
......@@ -20,4 +20,8 @@ fn main() {
2020 //~^ ERROR invalid format string: expected alignment specifier after `:` in format string; example: `{:>?}`
2121 println!("{0:#X>18}", 12345);
2222 //~^ ERROR invalid format string: expected alignment specifier after `:` in format string; example: `{:>?}`
23 format!("{+:}");
24 //~^ ERROR invalid format string: the `+` sign flag must appear after `:` in a format string
25 format!("{bar+:}");
26 //~^ ERROR invalid format string: the `+` sign flag must appear after `:` in a format string
2327}
tests/ui/fmt/format-string-wrong-order.stderr+17-1
......@@ -74,5 +74,21 @@ error: invalid format string: expected alignment specifier after `:` in format s
7474LL | println!("{0:#X>18}", 12345);
7575 | ^ expected `>` to occur after `:` in format string
7676
77error: aborting due to 10 previous errors
77error: invalid format string: the `+` sign flag must appear after `:` in a format string
78 --> $DIR/format-string-wrong-order.rs:23:15
79 |
80LL | format!("{+:}");
81 | ^ expected `:` before `+` sign flag in format string
82 |
83 = note: `+` comes after `:`, try `{:+}` instead of `{+}`
84
85error: invalid format string: the `+` sign flag must appear after `:` in a format string
86 --> $DIR/format-string-wrong-order.rs:25:18
87 |
88LL | format!("{bar+:}");
89 | ^ expected `:` before `+` sign flag in format string
90 |
91 = note: `+` comes after `:`, try `{:+}` instead of `{+}`
92
93error: aborting due to 12 previous errors
7894
tests/ui/parser/field-name-in-tuple-struct.rs created+6
......@@ -0,0 +1,6 @@
1// Provide diagnostics when the user writes field names in tuple struct.(issue#144595)
2
3struct Foo(a:u8,b:u8);
4//~^ ERROR expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:`
5//~| HELP if you meant to write a path, use a double colon:
6//~| HELP if you meant to create a regular struct, use curly braces:
tests/ui/parser/field-name-in-tuple-struct.stderr created+18
......@@ -0,0 +1,18 @@
1error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:`
2 --> $DIR/field-name-in-tuple-struct.rs:3:13
3 |
4LL | struct Foo(a:u8,b:u8);
5 | ^ expected one of 7 possible tokens
6 |
7help: if you meant to write a path, use a double colon:
8 |
9LL | struct Foo(a::u8,b:u8);
10 | +
11help: if you meant to create a regular struct, use curly braces:
12 |
13LL - struct Foo(a:u8,b:u8);
14LL + struct Foo{a:u8,b:u8}
15 |
16
17error: aborting due to 1 previous error
18
tests/ui/pattern/deref-patterns/needs-gate.stderr+5
......@@ -76,6 +76,11 @@ LL | match "str".to_owned() {
7676 | ---------------- this expression has type `String`
7777LL | "str" => {}
7878 | ^^^^^ expected `String`, found `&str`
79 |
80help: consider converting the `String` to a `&str` using `.as_str()`
81 |
82LL | match "str".to_owned().as_str() {
83 | +++++++++
7984
8085error[E0308]: mismatched types
8186 --> $DIR/needs-gate.rs:52:12
tests/ui/pattern/string-match-as-str-suggestion.fixed created+18
......@@ -0,0 +1,18 @@
1//@ run-rustfix
2
3fn main() {
4 let s = "yes".to_owned();
5
6 let _ = match s.as_str() {
7 "yes" => Some(true),
8 //~^ ERROR mismatched types
9 "no" => Some(false),
10 //~^ ERROR mismatched types
11 _ => None,
12 };
13
14 let s2 = String::from("hello");
15 if let "hello" = s2.as_str() {
16 //~^ ERROR mismatched types
17 }
18}
tests/ui/pattern/string-match-as-str-suggestion.rs created+18
......@@ -0,0 +1,18 @@
1//@ run-rustfix
2
3fn main() {
4 let s = "yes".to_owned();
5
6 let _ = match s {
7 "yes" => Some(true),
8 //~^ ERROR mismatched types
9 "no" => Some(false),
10 //~^ ERROR mismatched types
11 _ => None,
12 };
13
14 let s2 = String::from("hello");
15 if let "hello" = s2 {
16 //~^ ERROR mismatched types
17 }
18}
tests/ui/pattern/string-match-as-str-suggestion.stderr created+43
......@@ -0,0 +1,43 @@
1error[E0308]: mismatched types
2 --> $DIR/string-match-as-str-suggestion.rs:7:9
3 |
4LL | let _ = match s {
5 | - this expression has type `String`
6LL | "yes" => Some(true),
7 | ^^^^^ expected `String`, found `&str`
8 |
9help: consider converting the `String` to a `&str` using `.as_str()`
10 |
11LL | let _ = match s.as_str() {
12 | +++++++++
13
14error[E0308]: mismatched types
15 --> $DIR/string-match-as-str-suggestion.rs:9:9
16 |
17LL | let _ = match s {
18 | - this expression has type `String`
19...
20LL | "no" => Some(false),
21 | ^^^^ expected `String`, found `&str`
22 |
23help: consider converting the `String` to a `&str` using `.as_str()`
24 |
25LL | let _ = match s.as_str() {
26 | +++++++++
27
28error[E0308]: mismatched types
29 --> $DIR/string-match-as-str-suggestion.rs:15:12
30 |
31LL | if let "hello" = s2 {
32 | ^^^^^^^ -- this expression has type `String`
33 | |
34 | expected `String`, found `&str`
35 |
36help: consider converting the `String` to a `&str` using `.as_str()`
37 |
38LL | if let "hello" = s2.as_str() {
39 | +++++++++
40
41error: aborting due to 3 previous errors
42
43For more information about this error, try `rustc --explain E0308`.
triagebot.toml+1-1
......@@ -1050,7 +1050,7 @@ cc = ["@Nadrieril"]
10501050message = "Some changes occurred in cfg and check-cfg configuration"
10511051cc = ["@Urgau"]
10521052
1053[mentions."compiler/rustc_attr_parsing/src/attributes/diagnostic/check_cfg.rs"]
1053[mentions."compiler/rustc_attr_parsing/src/check_cfg.rs"]
10541054message = "Some changes occurred in check-cfg diagnostics"
10551055cc = ["@Urgau"]
10561056