From 0e2130c2c9726a243cacafae3d0c6fdf8284301f Mon Sep 17 00:00:00 2001 From: Evan Jones Date: Wed, 8 Oct 2025 15:51:21 -0400 Subject: [PATCH 01/14] std::thread spawn: Docs: Link to Builder::spawn; Make same. Replace "use this API instead" with a link to Builder::spawn. Edit the paragraph to make it slightly clearer. The Scope::spawn method already included a. Make the docs for the two nearly the same. --- library/std/src/thread/mod.rs | 5 ++--- library/std/src/thread/scoped.rs | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index fd7cce3f97db..78c85c0af644 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -620,9 +620,8 @@ impl Builder { /// (It is the responsibility of the program to either eventually join threads it /// creates or detach them; otherwise, a resource leak will result.) /// -/// This call will create a thread using default parameters of [`Builder`], if you -/// want to specify the stack size or the name of the thread, use this API -/// instead. +/// This function creates a thread with the default parameters. To specify the +/// new thread's stack size or the name, use [`Builder::spawn`]. /// /// As you can see in the signature of `spawn` there are two constraints on /// both the closure given to `spawn` and its return value, let's explain them: diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs index a4c0ca5417d0..2368ce4988d8 100644 --- a/library/std/src/thread/scoped.rs +++ b/library/std/src/thread/scoped.rs @@ -181,9 +181,8 @@ impl<'scope, 'env> Scope<'scope, 'env> { /// end of the scope. In that case, if the spawned thread panics, [`scope`] will /// panic after all threads are joined. /// - /// This call will create a thread using default parameters of [`Builder`]. - /// If you want to specify the stack size or the name of the thread, use - /// [`Builder::spawn_scoped`] instead. + /// This function creates a thread with the default parameters. To specify the + /// new thread's stack size or the name, use [`Builder::spawn_scoped`]. /// /// # Panics /// From 52cc311828925e306cd379376255b9239a6063ca Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 3 Oct 2025 11:55:38 +0200 Subject: [PATCH 02/14] Rename some functions Signed-off-by: Jonathan Brouwer --- compiler/rustc_attr_parsing/src/attributes/cfg.rs | 3 ++- compiler/rustc_attr_parsing/src/lib.rs | 2 +- compiler/rustc_expand/src/config.rs | 6 +++--- src/librustdoc/clean/cfg.rs | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 708556110797..2ed570d0ed7a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -21,7 +21,7 @@ pub const CFG_TEMPLATE: AttributeTemplate = template!( "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute" ); -pub fn parse_cfg_attr<'c, S: Stage>( +pub fn parse_cfg<'c, S: Stage>( cx: &'c mut AcceptContext<'_, '_, S>, args: &'c ArgParser<'_>, ) -> Option { @@ -300,3 +300,4 @@ impl EvalConfigResult { } } } + diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index f51cc8c4e8be..6875c7d2b686 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -105,7 +105,7 @@ mod session_diagnostics; mod target_checking; pub mod validate_attr; -pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr}; +pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg}; pub use attributes::cfg_old::*; pub use attributes::util::{is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version}; pub use context::{Early, Late, OmitDoc, ShouldEmit}; diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 2925e337071c..b3a3161391d4 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -13,7 +13,7 @@ use rustc_ast::{ use rustc_attr_parsing as attr; use rustc_attr_parsing::validate_attr::deny_builtin_meta_unsafety; use rustc_attr_parsing::{ - AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg_attr, + AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg, validate_attr, }; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; @@ -428,7 +428,7 @@ impl<'a> StripUnconfigured<'a> { node, self.features, emit_errors, - parse_cfg_attr, + parse_cfg, &CFG_TEMPLATE, ) else { // Cfg attribute was not parsable, give up @@ -488,7 +488,7 @@ impl<'a> StripUnconfigured<'a> { } /// FIXME: Still used by Rustdoc, should be removed after -pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItemInner> { +pub fn parse_cfg_old<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItemInner> { let span = meta_item.span; match meta_item.meta_item_list() { None => { diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 881a81b22f0f..6c77e41965dc 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -751,7 +751,7 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator } for attr in doc_cfg { if let Some(cfg_mi) = - attr.meta_item().and_then(|attr| rustc_expand::config::parse_cfg(attr, sess)) + attr.meta_item().and_then(|attr| rustc_expand::config::parse_cfg_old(attr, sess)) { match Cfg::parse(cfg_mi) { Ok(new_cfg) => cfg_info.current_cfg &= new_cfg, From e0c190f681627462bfb009929d04b0e3bc53e692 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 3 Oct 2025 12:00:46 +0200 Subject: [PATCH 03/14] Move `parse_cfg_attr` to rustc_attr_parsing Signed-off-by: Jonathan Brouwer --- compiler/rustc_attr_parsing/messages.ftl | 10 +++ .../rustc_attr_parsing/src/attributes/cfg.rs | 73 ++++++++++++++++++- compiler/rustc_attr_parsing/src/lib.rs | 4 +- .../src/session_diagnostics.rs | 19 +++++ compiler/rustc_expand/src/config.rs | 2 +- compiler/rustc_parse/messages.ftl | 7 -- compiler/rustc_parse/src/errors.rs | 28 ------- compiler/rustc_parse/src/lib.rs | 47 +----------- compiler/rustc_parse/src/parser/attr.rs | 21 ------ 9 files changed, 106 insertions(+), 105 deletions(-) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 8b6b762f4310..0710f8a8078d 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -264,3 +264,13 @@ attr_parsing_unused_multiple = attr_parsing_whole_archive_needs_static = linking modifier `whole-archive` is only compatible with `static` linking kind + +attr_parsing_limit_invalid = + `limit` must be a non-negative integer + .label = {$error_str} + +attr_parsing_cfg_attr_bad_delim = wrong `cfg_attr` delimiters + +attr_parsing_malformed_cfg_attr = malformed `cfg_attr` attribute input + .suggestion = missing condition and attribute + .note = for more information, visit diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 2ed570d0ed7a..c500dacedaac 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -1,17 +1,23 @@ -use rustc_ast::{LitKind, NodeId}; +use rustc_ast::token::Delimiter; +use rustc_ast::tokenstream::DelimSpan; +use rustc_ast::{AttrItem, Attribute, LitKind, MetaItemInner, NodeId, ast, token}; +use rustc_errors::PResult; use rustc_feature::{AttributeTemplate, Features, template}; use rustc_hir::RustcVersion; use rustc_hir::attrs::CfgEntry; +use rustc_parse::parser::{ForceCollect, Parser}; +use rustc_parse::{exp, parse_in}; use rustc_session::Session; use rustc_session::config::ExpectedValues; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::UNEXPECTED_CFGS; -use rustc_session::parse::feature_err; +use rustc_session::parse::{ParseSess, feature_err}; use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; use crate::context::{AcceptContext, ShouldEmit, Stage}; use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser}; +use crate::session_diagnostics::{CfgAttrBadDelim, MalformedCfgAttr, MetaBadDelimSugg}; use crate::{ CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, try_gate_cfg, }; @@ -301,3 +307,66 @@ impl EvalConfigResult { } } +pub fn parse_cfg_attr( + cfg_attr: &Attribute, + psess: &ParseSess, +) -> Option<(MetaItemInner, Vec<(AttrItem, Span)>)> { + const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; + const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ + "; + + match cfg_attr.get_normal_item().args { + ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens }) + if !tokens.is_empty() => + { + check_cfg_attr_bad_delim(psess, dspan, delim); + match parse_in(psess, tokens.clone(), "`cfg_attr` input", |p| { + parse_cfg_attr_internal(p) + }) { + Ok(r) => return Some(r), + Err(e) => { + e.with_help(format!("the valid syntax is `{CFG_ATTR_GRAMMAR_HELP}`")) + .with_note(CFG_ATTR_NOTE_REF) + .emit(); + } + } + } + _ => { + psess + .dcx() + .emit_err(MalformedCfgAttr { span: cfg_attr.span, sugg: CFG_ATTR_GRAMMAR_HELP }); + } + } + None +} + +fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) { + if let Delimiter::Parenthesis = delim { + return; + } + psess.dcx().emit_err(CfgAttrBadDelim { + span: span.entire(), + sugg: MetaBadDelimSugg { open: span.open, close: span.close }, + }); +} + +/// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. +fn parse_cfg_attr_internal<'a>( + parser: &mut Parser<'a>, +) -> PResult<'a, (ast::MetaItemInner, Vec<(ast::AttrItem, Span)>)> { + let cfg_predicate = parser.parse_meta_item_inner()?; + parser.expect(exp!(Comma))?; + + // Presumably, the majority of the time there will only be one attr. + let mut expanded_attrs = Vec::with_capacity(1); + while parser.token != token::Eof { + let lo = parser.token.span; + let item = parser.parse_attr_item(ForceCollect::Yes)?; + expanded_attrs.push((item, lo.to(parser.prev_token.span))); + if !parser.eat(exp!(Comma)) { + break; + } + } + + Ok((cfg_predicate, expanded_attrs)) +} diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 6875c7d2b686..bcd0d674c75f 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -105,7 +105,9 @@ mod session_diagnostics; mod target_checking; pub mod validate_attr; -pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg}; +pub use attributes::cfg::{ + CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, +}; pub use attributes::cfg_old::*; pub use attributes::util::{is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version}; pub use context::{Early, Late, OmitDoc, ShouldEmit}; diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 1194ac5872cb..db82776310b3 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -971,3 +971,22 @@ pub(crate) struct LimitInvalid<'a> { pub value_span: Span, pub error_str: &'a str, } + +#[derive(Diagnostic)] +#[diag(attr_parsing_cfg_attr_bad_delim)] +pub(crate) struct CfgAttrBadDelim { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sugg: MetaBadDelimSugg, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_malformed_cfg_attr)] +#[note] +pub(crate) struct MalformedCfgAttr { + #[primary_span] + #[suggestion(style = "verbose", code = "{sugg}")] + pub span: Span, + pub sugg: &'static str, +} diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index b3a3161391d4..ad90209c4c98 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -303,7 +303,7 @@ impl<'a> StripUnconfigured<'a> { let trace_attr = attr_into_trace(cfg_attr.clone(), sym::cfg_attr_trace); let Some((cfg_predicate, expanded_attrs)) = - rustc_parse::parse_cfg_attr(cfg_attr, &self.sess.psess) + rustc_attr_parsing::parse_cfg_attr(cfg_attr, &self.sess.psess) else { return vec![trace_attr]; }; diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index b1894ab92192..52a35c98a98b 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -122,7 +122,6 @@ parse_cannot_be_raw_lifetime = `{$ident}` cannot be a raw lifetime parse_catch_after_try = keyword `catch` cannot follow a `try` block .help = try using `match` on the result of the `try` block instead -parse_cfg_attr_bad_delim = wrong `cfg_attr` delimiters parse_colon_as_semi = statements are terminated with a semicolon .suggestion = use a semicolon instead @@ -573,10 +572,6 @@ parse_macro_rules_missing_bang = expected `!` after `macro_rules` parse_macro_rules_visibility = can't qualify macro_rules invocation with `{$vis}` .suggestion = try exporting the macro -parse_malformed_cfg_attr = malformed `cfg_attr` attribute input - .suggestion = missing condition and attribute - .note = for more information, visit - parse_malformed_loop_label = malformed loop label .suggestion = use the correct loop label format @@ -610,8 +605,6 @@ parse_maybe_report_ambiguous_plus = ambiguous `+` in a type .suggestion = use parentheses to disambiguate -parse_meta_bad_delim_suggestion = the delimiters should be `(` and `)` - parse_mismatched_closing_delimiter = mismatched closing delimiter: `{$delimiter}` .label_unmatched = mismatched closing delimiter .label_opening_candidate = closing delimiter possibly meant for this diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 1abeee6fe433..6d536aa850b3 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3351,34 +3351,6 @@ pub(crate) struct KwBadCase<'a> { pub kw: &'a str, } -#[derive(Diagnostic)] -#[diag(parse_cfg_attr_bad_delim)] -pub(crate) struct CfgAttrBadDelim { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub sugg: MetaBadDelimSugg, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion(parse_meta_bad_delim_suggestion, applicability = "machine-applicable")] -pub(crate) struct MetaBadDelimSugg { - #[suggestion_part(code = "(")] - pub open: Span, - #[suggestion_part(code = ")")] - pub close: Span, -} - -#[derive(Diagnostic)] -#[diag(parse_malformed_cfg_attr)] -#[note] -pub(crate) struct MalformedCfgAttr { - #[primary_span] - #[suggestion(style = "verbose", code = "{sugg}")] - pub span: Span, - pub sugg: &'static str, -} - #[derive(Diagnostic)] #[diag(parse_unknown_builtin_construct)] pub(crate) struct UnknownBuiltinConstruct { diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index c26c7b9122af..edec44ca9501 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -18,8 +18,8 @@ use std::str::Utf8Error; use std::sync::Arc; use rustc_ast as ast; -use rustc_ast::tokenstream::{DelimSpan, TokenStream}; -use rustc_ast::{AttrItem, Attribute, MetaItemInner, token}; +use rustc_ast::token; +use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; use rustc_errors::{Diag, EmissionGuarantee, FatalError, PResult, pluralize}; use rustc_session::parse::ParseSess; @@ -32,7 +32,6 @@ pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments"); #[macro_use] pub mod parser; use parser::Parser; -use rustc_ast::token::Delimiter; use crate::lexer::StripTokens; @@ -230,45 +229,3 @@ pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> Tok Some(krate.spans.inner_span), )) } - -pub fn parse_cfg_attr( - cfg_attr: &Attribute, - psess: &ParseSess, -) -> Option<(MetaItemInner, Vec<(AttrItem, Span)>)> { - const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; - const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ - "; - - match cfg_attr.get_normal_item().args { - ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens }) - if !tokens.is_empty() => - { - check_cfg_attr_bad_delim(psess, dspan, delim); - match parse_in(psess, tokens.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) { - Ok(r) => return Some(r), - Err(e) => { - e.with_help(format!("the valid syntax is `{CFG_ATTR_GRAMMAR_HELP}`")) - .with_note(CFG_ATTR_NOTE_REF) - .emit(); - } - } - } - _ => { - psess.dcx().emit_err(errors::MalformedCfgAttr { - span: cfg_attr.span, - sugg: CFG_ATTR_GRAMMAR_HELP, - }); - } - } - None -} - -fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) { - if let Delimiter::Parenthesis = delim { - return; - } - psess.dcx().emit_err(errors::CfgAttrBadDelim { - span: span.entire(), - sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close }, - }); -} diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index acd338156ce8..5725f4c36679 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -377,27 +377,6 @@ impl<'a> Parser<'a> { Ok(lit) } - /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. - pub fn parse_cfg_attr( - &mut self, - ) -> PResult<'a, (ast::MetaItemInner, Vec<(ast::AttrItem, Span)>)> { - let cfg_predicate = self.parse_meta_item_inner()?; - self.expect(exp!(Comma))?; - - // Presumably, the majority of the time there will only be one attr. - let mut expanded_attrs = Vec::with_capacity(1); - while self.token != token::Eof { - let lo = self.token.span; - let item = self.parse_attr_item(ForceCollect::Yes)?; - expanded_attrs.push((item, lo.to(self.prev_token.span))); - if !self.eat(exp!(Comma)) { - break; - } - } - - Ok((cfg_predicate, expanded_attrs)) - } - /// Matches `COMMASEP(meta_item_inner)`. pub fn parse_meta_seq_top(&mut self) -> PResult<'a, ThinVec> { // Presumably, the majority of the time there will only be one attr. From 7113d58c8e089517de95fab5d229f56616ba36f9 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Fri, 3 Oct 2025 13:24:45 +0200 Subject: [PATCH 04/14] Port `#[cfg_attr]` to the new attribute parsing infrastructure Signed-off-by: Jonathan Brouwer --- compiler/rustc_attr_parsing/messages.ftl | 12 +- .../rustc_attr_parsing/src/attributes/cfg.rs | 115 +++++++++++++----- compiler/rustc_attr_parsing/src/interface.rs | 64 ++++++++-- compiler/rustc_attr_parsing/src/parser.rs | 40 +++--- .../src/session_diagnostics.rs | 10 -- compiler/rustc_expand/src/config.rs | 12 +- 6 files changed, 171 insertions(+), 82 deletions(-) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 0710f8a8078d..a2a5f8ab1423 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -4,6 +4,8 @@ attr_parsing_as_needed_compatibility = attr_parsing_bundle_needs_static = linking modifier `bundle` is only compatible with `static` linking kind +attr_parsing_cfg_attr_bad_delim = wrong `cfg_attr` delimiters + attr_parsing_cfg_predicate_identifier = `cfg` predicate key must be an identifier @@ -264,13 +266,3 @@ attr_parsing_unused_multiple = attr_parsing_whole_archive_needs_static = linking modifier `whole-archive` is only compatible with `static` linking kind - -attr_parsing_limit_invalid = - `limit` must be a non-negative integer - .label = {$error_str} - -attr_parsing_cfg_attr_bad_delim = wrong `cfg_attr` delimiters - -attr_parsing_malformed_cfg_attr = malformed `cfg_attr` attribute input - .suggestion = missing condition and attribute - .note = for more information, visit diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index c500dacedaac..af94e8acaf68 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -1,10 +1,10 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; -use rustc_ast::{AttrItem, Attribute, LitKind, MetaItemInner, NodeId, ast, token}; -use rustc_errors::PResult; +use rustc_ast::{AttrItem, Attribute, CRATE_NODE_ID, LitKind, NodeId, ast, token}; +use rustc_errors::{Applicability, PResult}; use rustc_feature::{AttributeTemplate, Features, template}; -use rustc_hir::RustcVersion; use rustc_hir::attrs::CfgEntry; +use rustc_hir::{AttrPath, RustcVersion}; use rustc_parse::parser::{ForceCollect, Parser}; use rustc_parse::{exp, parse_in}; use rustc_session::Session; @@ -17,9 +17,12 @@ use thin_vec::ThinVec; use crate::context::{AcceptContext, ShouldEmit, Stage}; use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser}; -use crate::session_diagnostics::{CfgAttrBadDelim, MalformedCfgAttr, MetaBadDelimSugg}; +use crate::session_diagnostics::{ + AttributeParseError, AttributeParseErrorReason, CfgAttrBadDelim, MetaBadDelimSugg, +}; use crate::{ - CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, try_gate_cfg, + AttributeParser, CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, + try_gate_cfg, }; pub const CFG_TEMPLATE: AttributeTemplate = template!( @@ -27,6 +30,11 @@ pub const CFG_TEMPLATE: AttributeTemplate = template!( "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute" ); +const CFG_ATTR_TEMPLATE: AttributeTemplate = template!( + List: &["predicate, attr1, attr2, ..."], + "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute" +); + pub fn parse_cfg<'c, S: Stage>( cx: &'c mut AcceptContext<'_, '_, S>, args: &'c ArgParser<'_>, @@ -76,9 +84,7 @@ pub(crate) fn parse_cfg_entry( }, a @ (ArgParser::NoArgs | ArgParser::NameValue(_)) => { let Some(name) = meta.path().word_sym() else { - cx.emit_err(session_diagnostics::CfgPredicateIdentifier { - span: meta.path().span(), - }); + cx.expected_identifier(meta.path().span()); return None; }; parse_name_value(name, meta.path().span(), a.name_value(), meta.span(), cx)? @@ -87,7 +93,7 @@ pub(crate) fn parse_cfg_entry( MetaItemOrLitParser::Lit(lit) => match lit.kind { LitKind::Bool(b) => CfgEntry::Bool(b, lit.span), _ => { - cx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: lit.span }); + cx.expected_identifier(lit.span); return None; } }, @@ -155,9 +161,7 @@ fn parse_cfg_entry_target( // Then, parse it as a name-value item let Some(name) = sub_item.path().word_sym() else { - cx.emit_err(session_diagnostics::CfgPredicateIdentifier { - span: sub_item.path().span(), - }); + cx.expected_identifier(sub_item.path().span()); return None; }; let name = Symbol::intern(&format!("target_{name}")); @@ -309,32 +313,51 @@ impl EvalConfigResult { pub fn parse_cfg_attr( cfg_attr: &Attribute, - psess: &ParseSess, -) -> Option<(MetaItemInner, Vec<(AttrItem, Span)>)> { - const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; - const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ - "; - + sess: &Session, + features: Option<&Features>, +) -> Option<(CfgEntry, Vec<(AttrItem, Span)>)> { match cfg_attr.get_normal_item().args { ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens }) if !tokens.is_empty() => { - check_cfg_attr_bad_delim(psess, dspan, delim); - match parse_in(psess, tokens.clone(), "`cfg_attr` input", |p| { - parse_cfg_attr_internal(p) + check_cfg_attr_bad_delim(&sess.psess, dspan, delim); + match parse_in(&sess.psess, tokens.clone(), "`cfg_attr` input", |p| { + parse_cfg_attr_internal(p, sess, features, cfg_attr) }) { Ok(r) => return Some(r), Err(e) => { - e.with_help(format!("the valid syntax is `{CFG_ATTR_GRAMMAR_HELP}`")) - .with_note(CFG_ATTR_NOTE_REF) - .emit(); + let suggestions = CFG_ATTR_TEMPLATE.suggestions(cfg_attr.style, sym::cfg_attr); + e.with_span_suggestions( + cfg_attr.span, + "must be of the form", + suggestions, + Applicability::HasPlaceholders, + ) + .with_note(format!( + "for more information, visit <{}>", + CFG_ATTR_TEMPLATE.docs.expect("cfg_attr has docs") + )) + .emit(); } } } _ => { - psess - .dcx() - .emit_err(MalformedCfgAttr { span: cfg_attr.span, sugg: CFG_ATTR_GRAMMAR_HELP }); + let (span, reason) = if let ast::AttrArgs::Delimited(ast::DelimArgs { dspan, .. }) = + cfg_attr.get_normal_item().args + { + (dspan.entire(), AttributeParseErrorReason::ExpectedAtLeastOneArgument) + } else { + (cfg_attr.span, AttributeParseErrorReason::ExpectedList) + }; + + sess.dcx().emit_err(AttributeParseError { + span, + attr_span: cfg_attr.span, + template: CFG_ATTR_TEMPLATE, + attribute: AttrPath::from_ast(&cfg_attr.get_normal_item().path), + reason, + attr_style: cfg_attr.style, + }); } } None @@ -353,8 +376,42 @@ fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. fn parse_cfg_attr_internal<'a>( parser: &mut Parser<'a>, -) -> PResult<'a, (ast::MetaItemInner, Vec<(ast::AttrItem, Span)>)> { - let cfg_predicate = parser.parse_meta_item_inner()?; + sess: &'a Session, + features: Option<&Features>, + attribute: &Attribute, +) -> PResult<'a, (CfgEntry, Vec<(ast::AttrItem, Span)>)> { + // Parse cfg predicate + let pred_start = parser.token.span; + let meta = MetaItemOrLitParser::parse_single(parser, ShouldEmit::ErrorsAndLints)?; + let pred_span = pred_start.with_hi(parser.token.span.hi()); + + let cfg_predicate = AttributeParser::parse_single_args( + sess, + attribute.span, + attribute.style, + AttrPath { + segments: attribute + .ident_path() + .expect("cfg_attr is not a doc comment") + .into_boxed_slice(), + span: attribute.span, + }, + pred_span, + CRATE_NODE_ID, + features, + ShouldEmit::ErrorsAndLints, + &meta, + parse_cfg_entry, + &CFG_ATTR_TEMPLATE, + ) + .ok_or_else(|| { + let mut diag = sess.dcx().struct_err( + "cfg_entry parsing failing with `ShouldEmit::ErrorsAndLints` should emit a error.", + ); + diag.downgrade_to_delayed_bug(); + diag + })?; + parser.expect(exp!(Comma))?; // Presumably, the majority of the time there will only be one attr. diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 8f2de4af14e0..b8ef11c26d80 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use rustc_ast as ast; -use rustc_ast::NodeId; +use rustc_ast::{AttrStyle, NodeId}; use rustc_errors::DiagCtxtHandle; use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::attrs::AttributeKind; @@ -62,7 +62,8 @@ impl<'sess> AttributeParser<'sess, Early> { ) } - /// Usually you want `parse_limited`, which defaults to no errors. + /// This does the same as `parse_limited`, except it has a `should_emit` parameter which allows it to emit errors. + /// Usually you want `parse_limited`, which emits no errors. pub fn parse_limited_should_emit( sess: &'sess Session, attrs: &[ast::Attribute], @@ -86,6 +87,13 @@ impl<'sess> AttributeParser<'sess, Early> { parsed.pop() } + /// This method allows you to parse a list of attributes *before* `rustc_ast_lowering`. + /// This can be used for attributes that would be removed before `rustc_ast_lowering`, such as attributes on macro calls. + /// + /// Try to use this as little as possible. Attributes *should* be lowered during + /// `rustc_ast_lowering`. Some attributes require access to features to parse, which would + /// crash if you tried to do so through [`parse_limited_all`](Self::parse_limited_all). + /// Therefore, if `parse_only` is None, then features *must* be provided. pub fn parse_limited_all( sess: &'sess Session, attrs: &[ast::Attribute], @@ -111,6 +119,8 @@ impl<'sess> AttributeParser<'sess, Early> { ) } + /// This method parses a single attribute, using `parse_fn`. + /// This is useful if you already know what exact attribute this is, and want to parse it. pub fn parse_single( sess: &'sess Session, attr: &ast::Attribute, @@ -121,13 +131,6 @@ impl<'sess> AttributeParser<'sess, Early> { parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> Option, template: &AttributeTemplate, ) -> Option { - let mut parser = Self { - features, - tools: Vec::new(), - parse_only: None, - sess, - stage: Early { emit_errors }, - }; let ast::AttrKind::Normal(normal_attr) = &attr.kind else { panic!("parse_single called on a doc attr") }; @@ -136,6 +139,43 @@ impl<'sess> AttributeParser<'sess, Early> { let meta_parser = MetaItemParser::from_attr(normal_attr, &parts, &sess.psess, emit_errors)?; let path = meta_parser.path(); let args = meta_parser.args(); + Self::parse_single_args( + sess, + attr.span, + attr.style, + path.get_attribute_path(), + target_span, + target_node_id, + features, + emit_errors, + args, + parse_fn, + template, + ) + } + + /// This method is equivalent to `parse_single`, but parses arguments using `parse_fn` using manually created `args`. + /// This is useful when you want to parse other things than attributes using attribute parsers. + pub fn parse_single_args( + sess: &'sess Session, + attr_span: Span, + attr_style: AttrStyle, + attr_path: AttrPath, + target_span: Span, + target_node_id: NodeId, + features: Option<&'sess Features>, + emit_errors: ShouldEmit, + args: &I, + parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &I) -> Option, + template: &AttributeTemplate, + ) -> Option { + let mut parser = Self { + features, + tools: Vec::new(), + parse_only: None, + sess, + stage: Early { emit_errors }, + }; let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext { shared: SharedContext { cx: &mut parser, @@ -145,10 +185,10 @@ impl<'sess> AttributeParser<'sess, Early> { crate::lints::emit_attribute_lint(&lint, sess); }, }, - attr_span: attr.span, - attr_style: attr.style, + attr_span, + attr_style, template, - attr_path: path.get_attribute_path(), + attr_path, }; parse_fn(&mut cx, args) } diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 3f4f56790157..7474471f2fe0 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -8,7 +8,7 @@ use std::fmt::{Debug, Display}; use rustc_ast::token::{self, Delimiter, MetaVarKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path}; +use rustc_ast::{AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path}; use rustc_ast_pretty::pprust; use rustc_errors::{Diag, PResult}; use rustc_hir::{self as hir, AttrPath}; @@ -124,7 +124,11 @@ impl<'a> ArgParser<'a> { return None; } - Self::List(MetaItemListParser::new(args, psess, should_emit)?) + Self::List( + MetaItemListParser::new(&args.tokens, args.dspan.entire(), psess, should_emit) + .map_err(|e| should_emit.emit_err(e)) + .ok()?, + ) } AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser { eq_span: *eq_span, @@ -186,7 +190,15 @@ pub enum MetaItemOrLitParser<'a> { Err(Span, ErrorGuaranteed), } -impl<'a> MetaItemOrLitParser<'a> { +impl<'sess> MetaItemOrLitParser<'sess> { + pub fn parse_single( + parser: &mut Parser<'sess>, + should_emit: ShouldEmit, + ) -> PResult<'sess, MetaItemOrLitParser<'static>> { + let mut this = MetaItemListParserContext { parser, should_emit }; + this.parse_meta_item_inner() + } + pub fn span(&self) -> Span { match self { MetaItemOrLitParser::MetaItemParser(generic_meta_item_parser) => { @@ -204,7 +216,7 @@ impl<'a> MetaItemOrLitParser<'a> { } } - pub fn meta_item(&self) -> Option<&MetaItemParser<'a>> { + pub fn meta_item(&self) -> Option<&MetaItemParser<'sess>> { match self { MetaItemOrLitParser::MetaItemParser(parser) => Some(parser), _ => None, @@ -542,23 +554,13 @@ pub struct MetaItemListParser<'a> { } impl<'a> MetaItemListParser<'a> { - fn new<'sess>( - delim: &'a DelimArgs, + pub(crate) fn new<'sess>( + tokens: &'a TokenStream, + span: Span, psess: &'sess ParseSess, should_emit: ShouldEmit, - ) -> Option { - match MetaItemListParserContext::parse( - delim.tokens.clone(), - psess, - delim.dspan.entire(), - should_emit, - ) { - Ok(s) => Some(s), - Err(e) => { - should_emit.emit_err(e); - None - } - } + ) -> Result> { + MetaItemListParserContext::parse(tokens.clone(), psess, span, should_emit) } /// Lets you pick and choose as what you want to parse each element in the list diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index db82776310b3..7b82f3baec09 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -980,13 +980,3 @@ pub(crate) struct CfgAttrBadDelim { #[subdiagnostic] pub sugg: MetaBadDelimSugg, } - -#[derive(Diagnostic)] -#[diag(attr_parsing_malformed_cfg_attr)] -#[note] -pub(crate) struct MalformedCfgAttr { - #[primary_span] - #[suggestion(style = "verbose", code = "{sugg}")] - pub span: Span, - pub sugg: &'static str, -} diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index ad90209c4c98..8278c29570b7 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -303,7 +303,7 @@ impl<'a> StripUnconfigured<'a> { let trace_attr = attr_into_trace(cfg_attr.clone(), sym::cfg_attr_trace); let Some((cfg_predicate, expanded_attrs)) = - rustc_attr_parsing::parse_cfg_attr(cfg_attr, &self.sess.psess) + rustc_attr_parsing::parse_cfg_attr(cfg_attr, &self.sess, self.features) else { return vec![trace_attr]; }; @@ -318,7 +318,15 @@ impl<'a> StripUnconfigured<'a> { ); } - if !attr::cfg_matches(&cfg_predicate, &self.sess, self.lint_node_id, self.features) { + if !attr::eval_config_entry( + self.sess, + &cfg_predicate, + ast::CRATE_NODE_ID, + self.features, + ShouldEmit::ErrorsAndLints, + ) + .as_bool() + { return vec![trace_attr]; } From 090dad00a9d464809d0c7514b4010a7b5edbfa82 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Tue, 14 Oct 2025 19:59:38 +0200 Subject: [PATCH 05/14] Changes in uitests for `cfg_attr` Signed-off-by: Jonathan Brouwer --- tests/ui/attributes/malformed-attrs.stderr | 9 +- tests/ui/cfg/cfg-path-error.rs | 16 +- tests/ui/cfg/cfg-path-error.stderr | 45 ++++-- tests/ui/cfg/cfg-target-compact-errors.rs | 2 +- tests/ui/cfg/cfg-target-compact-errors.stderr | 11 +- .../cfg-attr-parse.stderr | 48 +++--- .../cfg-attr-syntax-validation.rs | 10 +- .../cfg-attr-syntax-validation.stderr | 30 ++-- .../cfg_attr-attr-syntax-validation.rs | 50 ++++++ .../cfg_attr-attr-syntax-validation.stderr | 144 ++++++++++++++++++ tests/ui/link-native-libs/issue-43925.rs | 2 +- tests/ui/link-native-libs/issue-43925.stderr | 28 +++- .../link-attr-validation-late.rs | 2 +- .../link-attr-validation-late.stderr | 25 ++- .../malformed/malformed-special-attrs.stderr | 20 ++- .../removing-extern-crate-malformed-cfg.fixed | 1 + .../removing-extern-crate-malformed-cfg.rs | 1 + ...removing-extern-crate-malformed-cfg.stderr | 26 ++-- 18 files changed, 384 insertions(+), 86 deletions(-) create mode 100644 tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.rs create mode 100644 tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index 70ab3fb13c49..f0d2c100f030 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -9,17 +9,16 @@ LL | #[cfg] | = note: for more information, visit -error: malformed `cfg_attr` attribute input +error[E0539]: malformed `cfg_attr` attribute input --> $DIR/malformed-attrs.rs:103:1 | LL | #[cfg_attr] | ^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit -help: missing condition and attribute - | -LL | #[cfg_attr(condition, attribute, other_attribute, ...)] - | ++++++++++++++++++++++++++++++++++++++++++++ error[E0463]: can't find crate for `wloop` --> $DIR/malformed-attrs.rs:209:1 diff --git a/tests/ui/cfg/cfg-path-error.rs b/tests/ui/cfg/cfg-path-error.rs index 9db1f190bdc0..f22e6be32f3e 100644 --- a/tests/ui/cfg/cfg-path-error.rs +++ b/tests/ui/cfg/cfg-path-error.rs @@ -3,19 +3,27 @@ #![allow(unexpected_cfgs)] // invalid cfgs #[cfg(any(foo, foo::bar))] -//~^ERROR `cfg` predicate key must be an identifier +//~^ ERROR malformed `cfg` attribute input +//~| NOTE expected a valid identifier here +//~| NOTE for more information, visit fn foo1() {} #[cfg(any(foo::bar, foo))] -//~^ERROR `cfg` predicate key must be an identifier +//~^ ERROR malformed `cfg` attribute input +//~| NOTE expected a valid identifier here +//~| NOTE for more information, visit fn foo2() {} #[cfg(all(foo, foo::bar))] -//~^ERROR `cfg` predicate key must be an identifier +//~^ ERROR malformed `cfg` attribute input +//~| NOTE expected a valid identifier here +//~| NOTE for more information, visit fn foo3() {} #[cfg(all(foo::bar, foo))] -//~^ERROR `cfg` predicate key must be an identifier +//~^ ERROR malformed `cfg` attribute input +//~| NOTE expected a valid identifier here +//~| NOTE for more information, visit fn foo4() {} fn main() {} diff --git a/tests/ui/cfg/cfg-path-error.stderr b/tests/ui/cfg/cfg-path-error.stderr index 4f68fa32a9ac..bb9b7039c8a3 100644 --- a/tests/ui/cfg/cfg-path-error.stderr +++ b/tests/ui/cfg/cfg-path-error.stderr @@ -1,26 +1,47 @@ -error: `cfg` predicate key must be an identifier - --> $DIR/cfg-path-error.rs:5:16 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-path-error.rs:5:1 | LL | #[cfg(any(foo, foo::bar))] - | ^^^^^^^^ + | ^^^^^^^^^^^^^^^--------^^^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#[cfg(predicate)]` + | + = note: for more information, visit -error: `cfg` predicate key must be an identifier - --> $DIR/cfg-path-error.rs:9:11 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-path-error.rs:11:1 | LL | #[cfg(any(foo::bar, foo))] - | ^^^^^^^^ + | ^^^^^^^^^^--------^^^^^^^^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#[cfg(predicate)]` + | + = note: for more information, visit -error: `cfg` predicate key must be an identifier - --> $DIR/cfg-path-error.rs:13:16 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-path-error.rs:17:1 | LL | #[cfg(all(foo, foo::bar))] - | ^^^^^^^^ + | ^^^^^^^^^^^^^^^--------^^^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#[cfg(predicate)]` + | + = note: for more information, visit -error: `cfg` predicate key must be an identifier - --> $DIR/cfg-path-error.rs:17:11 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-path-error.rs:23:1 | LL | #[cfg(all(foo::bar, foo))] - | ^^^^^^^^ + | ^^^^^^^^^^--------^^^^^^^^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#[cfg(predicate)]` + | + = note: for more information, visit error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/cfg/cfg-target-compact-errors.rs b/tests/ui/cfg/cfg-target-compact-errors.rs index cfb19c58a197..1ce68330c762 100644 --- a/tests/ui/cfg/cfg-target-compact-errors.rs +++ b/tests/ui/cfg/cfg-target-compact-errors.rs @@ -19,7 +19,7 @@ fn three() {} fn four() {} #[cfg(target(clippy::os = "linux"))] -//~^ ERROR `cfg` predicate key must be an identifier +//~^ ERROR malformed `cfg` attribute input fn five() {} fn main() {} diff --git a/tests/ui/cfg/cfg-target-compact-errors.stderr b/tests/ui/cfg/cfg-target-compact-errors.stderr index cf61f94278a0..3ca1b73e0c09 100644 --- a/tests/ui/cfg/cfg-target-compact-errors.stderr +++ b/tests/ui/cfg/cfg-target-compact-errors.stderr @@ -42,11 +42,16 @@ LL | #[cfg(target(true))] | = note: for more information, visit -error: `cfg` predicate key must be an identifier - --> $DIR/cfg-target-compact-errors.rs:21:14 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-target-compact-errors.rs:21:1 | LL | #[cfg(target(clippy::os = "linux"))] - | ^^^^^^^^^^ + | ^^^^^^^^^^^^^----------^^^^^^^^^^^^^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#[cfg(predicate)]` + | + = note: for more information, visit error: aborting due to 5 previous errors diff --git a/tests/ui/conditional-compilation/cfg-attr-parse.stderr b/tests/ui/conditional-compilation/cfg-attr-parse.stderr index 76f199caace3..b08915e93421 100644 --- a/tests/ui/conditional-compilation/cfg-attr-parse.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-parse.stderr @@ -1,49 +1,56 @@ -error: malformed `cfg_attr` attribute input +error[E0539]: malformed `cfg_attr` attribute input --> $DIR/cfg-attr-parse.rs:4:1 | LL | #[cfg_attr()] - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^--^ + | | | + | | expected at least 1 argument here + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit -help: missing condition and attribute - | -LL | #[cfg_attr(condition, attribute, other_attribute, ...)] - | ++++++++++++++++++++++++++++++++++++++++++ error: expected `,`, found end of `cfg_attr` input --> $DIR/cfg-attr-parse.rs:8:17 | LL | #[cfg_attr(all())] - | ^ expected `,` + | ----------------^- + | | | + | | expected `,` + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | - = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` = note: for more information, visit error: expected identifier, found `,` --> $DIR/cfg-attr-parse.rs:16:18 | LL | #[cfg_attr(all(),,)] - | ^ expected identifier + | -----------------^-- + | | | + | | expected identifier + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | - = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` = note: for more information, visit error: expected identifier, found `,` --> $DIR/cfg-attr-parse.rs:28:28 | LL | #[cfg_attr(all(), must_use,,)] - | ^ expected identifier + | ---------------------------^-- + | | | + | | expected identifier + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | - = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` = note: for more information, visit error: expected identifier, found `,` --> $DIR/cfg-attr-parse.rs:40:40 | LL | #[cfg_attr(all(), must_use, deprecated,,)] - | ^ expected identifier + | ---------------------------------------^-- + | | | + | | expected identifier + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | - = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` = note: for more information, visit error: wrong `cfg_attr` delimiters @@ -62,9 +69,11 @@ error: expected identifier, found `,` --> $DIR/cfg-attr-parse.rs:44:18 | LL | #[cfg_attr[all(),,]] - | ^ expected identifier + | -----------------^-- + | | | + | | expected identifier + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | - = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` = note: for more information, visit error: wrong `cfg_attr` delimiters @@ -83,10 +92,13 @@ error: expected identifier, found `,` --> $DIR/cfg-attr-parse.rs:50:18 | LL | #[cfg_attr{all(),,}] - | ^ expected identifier + | -----------------^-- + | | | + | | expected identifier + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | - = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` = note: for more information, visit error: aborting due to 9 previous errors +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs index 2c84a966f904..7d4fd206c6b5 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs @@ -22,10 +22,16 @@ struct S3; //~| NOTE for more information, visit struct S4; -#[cfg("str")] //~ ERROR `cfg` predicate key must be an identifier +#[cfg("str")] +//~^ ERROR malformed `cfg` attribute input +//~| NOTE expected a valid identifier here +//~| NOTE for more information, visit struct S5; -#[cfg(a::b)] //~ ERROR `cfg` predicate key must be an identifier +#[cfg(a::b)] +//~^ ERROR malformed `cfg` attribute input +//~| NOTE expected a valid identifier here +//~| NOTE for more information, visit struct S6; #[cfg(a())] //~ ERROR invalid predicate `a` diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr index 59ff611e0661..e73b20f2d5d3 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr @@ -42,26 +42,36 @@ LL | #[cfg(a, b)] | = note: for more information, visit -error: `cfg` predicate key must be an identifier - --> $DIR/cfg-attr-syntax-validation.rs:25:7 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-attr-syntax-validation.rs:25:1 | LL | #[cfg("str")] - | ^^^^^ + | ^^^^^^-----^^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#[cfg(predicate)]` + | + = note: for more information, visit -error: `cfg` predicate key must be an identifier - --> $DIR/cfg-attr-syntax-validation.rs:28:7 +error[E0539]: malformed `cfg` attribute input + --> $DIR/cfg-attr-syntax-validation.rs:31:1 | LL | #[cfg(a::b)] - | ^^^^ + | ^^^^^^----^^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#[cfg(predicate)]` + | + = note: for more information, visit error[E0537]: invalid predicate `a` - --> $DIR/cfg-attr-syntax-validation.rs:31:7 + --> $DIR/cfg-attr-syntax-validation.rs:37:7 | LL | #[cfg(a())] | ^^^ error[E0539]: malformed `cfg` attribute input - --> $DIR/cfg-attr-syntax-validation.rs:34:1 + --> $DIR/cfg-attr-syntax-validation.rs:40:1 | LL | #[cfg(a = 10)] | ^^^^^^^^^^--^^ @@ -72,7 +82,7 @@ LL | #[cfg(a = 10)] = note: for more information, visit error[E0539]: malformed `cfg` attribute input - --> $DIR/cfg-attr-syntax-validation.rs:39:1 + --> $DIR/cfg-attr-syntax-validation.rs:45:1 | LL | #[cfg(a = b"hi")] | ^^^^^^^^^^-^^^^^^ @@ -82,7 +92,7 @@ LL | #[cfg(a = b"hi")] = note: expected a normal string literal, not a byte string literal error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable - --> $DIR/cfg-attr-syntax-validation.rs:45:25 + --> $DIR/cfg-attr-syntax-validation.rs:51:25 | LL | #[cfg(feature = $expr)] | ^^^^^ diff --git a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.rs new file mode 100644 index 000000000000..c08762db8aa9 --- /dev/null +++ b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.rs @@ -0,0 +1,50 @@ +#[cfg_attr] +//~^ ERROR malformed `cfg_attr` attribute +struct S1; + +#[cfg_attr = 10] +//~^ ERROR malformed `cfg_attr` attribute +struct S2; + +#[cfg_attr()] +//~^ ERROR malformed `cfg_attr` attribute +struct S3; + +#[cfg_attr("str")] //~ ERROR malformed `cfg_attr` attribute input +struct S5; + +#[cfg_attr(a::b)] //~ ERROR malformed `cfg_attr` attribute input +struct S6; + +#[cfg_attr(a())] //~ ERROR invalid predicate `a` +struct S7; + +#[cfg_attr(a = 10)] //~ ERROR malformed `cfg_attr` attribute input +struct S8; + +#[cfg_attr(a = b"hi")] //~ ERROR malformed `cfg_attr` attribute input +struct S9; + +macro_rules! generate_s10 { + ($expr: expr) => { + #[cfg_attr(feature = $expr)] + //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable + struct S10; + } +} + +generate_s10!(concat!("nonexistent")); + +#[cfg_attr(true)] //~ ERROR expected `,`, found end of `cfg_attr` input +struct S11; + +#[cfg_attr(true, unknown_attribute)] //~ ERROR cannot find attribute `unknown_attribute` in this scope +struct S12; + +#[cfg_attr(true, link_section)] //~ ERROR malformed `link_section` attribute input +struct S13; + +#[cfg_attr(true, inline())] //~ ERROR malformed `inline` attribute input +fn f1() {} + +fn main() {} diff --git a/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr new file mode 100644 index 000000000000..99117af70dc7 --- /dev/null +++ b/tests/ui/conditional-compilation/cfg_attr-attr-syntax-validation.stderr @@ -0,0 +1,144 @@ +error[E0539]: malformed `cfg_attr` attribute input + --> $DIR/cfg_attr-attr-syntax-validation.rs:1:1 + | +LL | #[cfg_attr] + | ^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` + | + = note: for more information, visit + +error[E0539]: malformed `cfg_attr` attribute input + --> $DIR/cfg_attr-attr-syntax-validation.rs:5:1 + | +LL | #[cfg_attr = 10] + | ^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` + | + = note: for more information, visit + +error[E0539]: malformed `cfg_attr` attribute input + --> $DIR/cfg_attr-attr-syntax-validation.rs:9:1 + | +LL | #[cfg_attr()] + | ^^^^^^^^^^--^ + | | | + | | expected at least 1 argument here + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` + | + = note: for more information, visit + +error[E0539]: malformed `cfg_attr` attribute input + --> $DIR/cfg_attr-attr-syntax-validation.rs:13:1 + | +LL | #[cfg_attr("str")] + | ^^^^^^^^^^^-----^^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` + | + = note: for more information, visit + +error[E0539]: malformed `cfg_attr` attribute input + --> $DIR/cfg_attr-attr-syntax-validation.rs:16:1 + | +LL | #[cfg_attr(a::b)] + | ^^^^^^^^^^^----^^ + | | | + | | expected a valid identifier here + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` + | + = note: for more information, visit + +error[E0537]: invalid predicate `a` + --> $DIR/cfg_attr-attr-syntax-validation.rs:19:12 + | +LL | #[cfg_attr(a())] + | ^^^ + +error[E0539]: malformed `cfg_attr` attribute input + --> $DIR/cfg_attr-attr-syntax-validation.rs:22:1 + | +LL | #[cfg_attr(a = 10)] + | ^^^^^^^^^^^^^^^--^^ + | | | + | | expected a string literal here + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` + | + = note: for more information, visit + +error[E0539]: malformed `cfg_attr` attribute input + --> $DIR/cfg_attr-attr-syntax-validation.rs:25:1 + | +LL | #[cfg_attr(a = b"hi")] + | ^^^^^^^^^^^^^^^-^^^^^^ + | | + | help: consider removing the prefix + | + = note: expected a normal string literal, not a byte string literal + +error: expected `,`, found end of `cfg_attr` input + --> $DIR/cfg_attr-attr-syntax-validation.rs:38:16 + | +LL | #[cfg_attr(true)] + | ---------------^- + | | | + | | expected `,` + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` + | + = note: for more information, visit + +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable + --> $DIR/cfg_attr-attr-syntax-validation.rs:30:30 + | +LL | #[cfg_attr(feature = $expr)] + | ---------------------^^^^^-- help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` +... +LL | generate_s10!(concat!("nonexistent")); + | ------------------------------------- in this macro invocation + | + = note: for more information, visit + = note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot find attribute `unknown_attribute` in this scope + --> $DIR/cfg_attr-attr-syntax-validation.rs:41:18 + | +LL | #[cfg_attr(true, unknown_attribute)] + | ^^^^^^^^^^^^^^^^^ + +error[E0539]: malformed `link_section` attribute input + --> $DIR/cfg_attr-attr-syntax-validation.rs:44:18 + | +LL | #[cfg_attr(true, link_section)] + | ^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]` + | + = note: for more information, visit + +error[E0805]: malformed `inline` attribute input + --> $DIR/cfg_attr-attr-syntax-validation.rs:47:18 + | +LL | #[cfg_attr(true, inline())] + | ^^^^^^-- + | | + | expected a single argument here + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[cfg_attr(true, inline())] +LL + #[cfg_attr(true, #[inline(always)])] + | +LL - #[cfg_attr(true, inline())] +LL + #[cfg_attr(true, #[inline(never)])] + | +LL - #[cfg_attr(true, inline())] +LL + #[cfg_attr(true, #[inline])] + | + +error: aborting due to 13 previous errors + +Some errors have detailed explanations: E0537, E0539, E0805. +For more information about an error, try `rustc --explain E0537`. diff --git a/tests/ui/link-native-libs/issue-43925.rs b/tests/ui/link-native-libs/issue-43925.rs index e3ce71352c06..09248db5a621 100644 --- a/tests/ui/link-native-libs/issue-43925.rs +++ b/tests/ui/link-native-libs/issue-43925.rs @@ -1,6 +1,6 @@ #[link(name = "foo", cfg("rlib"))] //~^ ERROR link cfg is unstable -//~| ERROR `cfg` predicate key must be an identifier +//~| ERROR malformed `link` attribute input extern "C" {} fn main() {} diff --git a/tests/ui/link-native-libs/issue-43925.stderr b/tests/ui/link-native-libs/issue-43925.stderr index 82d204222dfd..68a020546c14 100644 --- a/tests/ui/link-native-libs/issue-43925.stderr +++ b/tests/ui/link-native-libs/issue-43925.stderr @@ -7,12 +7,32 @@ LL | #[link(name = "foo", cfg("rlib"))] = help: add `#![feature(link_cfg)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `cfg` predicate key must be an identifier - --> $DIR/issue-43925.rs:1:26 +error[E0539]: malformed `link` attribute input + --> $DIR/issue-43925.rs:1:1 | LL | #[link(name = "foo", cfg("rlib"))] - | ^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^------^^^ + | | + | expected a valid identifier here + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "foo", cfg("rlib"))] +LL + #[link(name = "...")] + | +LL - #[link(name = "foo", cfg("rlib"))] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "foo", cfg("rlib"))] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "foo", cfg("rlib"))] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0658`. +Some errors have detailed explanations: E0539, E0658. +For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/link-native-libs/link-attr-validation-late.rs b/tests/ui/link-native-libs/link-attr-validation-late.rs index d2947b5f61af..c24acca0d840 100644 --- a/tests/ui/link-native-libs/link-attr-validation-late.rs +++ b/tests/ui/link-native-libs/link-attr-validation-late.rs @@ -22,7 +22,7 @@ extern "C" {} #[link(name = "...", modifiers())] //~ ERROR malformed `link` attribute input #[link(name = "...", cfg)] //~ ERROR malformed `link` attribute input #[link(name = "...", cfg = "literal")] //~ ERROR malformed `link` attribute input -#[link(name = "...", cfg("literal"))] //~ ERROR `cfg` predicate key must be an identifier +#[link(name = "...", cfg("literal"))] //~ ERROR malformed `link` attribute input #[link(name = "...", wasm_import_module)] //~ ERROR malformed `link` attribute input #[link(name = "...", wasm_import_module())] //~ ERROR malformed `link` attribute input extern "C" {} diff --git a/tests/ui/link-native-libs/link-attr-validation-late.stderr b/tests/ui/link-native-libs/link-attr-validation-late.stderr index 834dca0bc0bb..106b7cebc99f 100644 --- a/tests/ui/link-native-libs/link-attr-validation-late.stderr +++ b/tests/ui/link-native-libs/link-attr-validation-late.stderr @@ -367,11 +367,30 @@ LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", | = and 1 other candidate -error: `cfg` predicate key must be an identifier - --> $DIR/link-attr-validation-late.rs:25:26 +error[E0539]: malformed `link` attribute input + --> $DIR/link-attr-validation-late.rs:25:1 | LL | #[link(name = "...", cfg("literal"))] - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^---------^^^ + | | + | expected a valid identifier here + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[link(name = "...", cfg("literal"))] +LL + #[link(name = "...")] + | +LL - #[link(name = "...", cfg("literal"))] +LL + #[link(name = "...", import_name_type = "decorated|noprefix|undecorated")] + | +LL - #[link(name = "...", cfg("literal"))] +LL + #[link(name = "...", kind = "dylib|static|...")] + | +LL - #[link(name = "...", cfg("literal"))] +LL + #[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")] + | + = and 1 other candidate error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:26:1 diff --git a/tests/ui/malformed/malformed-special-attrs.stderr b/tests/ui/malformed/malformed-special-attrs.stderr index b6a1a6b50e46..91e5939eb1f9 100644 --- a/tests/ui/malformed/malformed-special-attrs.stderr +++ b/tests/ui/malformed/malformed-special-attrs.stderr @@ -1,27 +1,24 @@ -error: malformed `cfg_attr` attribute input +error[E0539]: malformed `cfg_attr` attribute input --> $DIR/malformed-special-attrs.rs:1:1 | LL | #[cfg_attr] | ^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit -help: missing condition and attribute - | -LL | #[cfg_attr(condition, attribute, other_attribute, ...)] - | ++++++++++++++++++++++++++++++++++++++++++++ -error: malformed `cfg_attr` attribute input +error[E0539]: malformed `cfg_attr` attribute input --> $DIR/malformed-special-attrs.rs:4:1 | LL | #[cfg_attr = ""] | ^^^^^^^^^^^^^^^^ + | | + | expected this to be a list + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | = note: for more information, visit -help: missing condition and attribute - | -LL - #[cfg_attr = ""] -LL + #[cfg_attr(condition, attribute, other_attribute, ...)] - | error: malformed `derive` attribute input --> $DIR/malformed-special-attrs.rs:7:1 @@ -37,3 +34,4 @@ LL | #[derive = ""] error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.fixed b/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.fixed index 028f86eb0a3e..b4b47dc886be 100644 --- a/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.fixed +++ b/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.fixed @@ -1,6 +1,7 @@ //@ edition:2018 //@ aux-build: remove-extern-crate.rs //@ run-rustfix +//@ rustfix-only-machine-applicable #![warn(rust_2018_idioms)] diff --git a/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.rs b/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.rs index 1acf531a6619..f3c591a656ad 100644 --- a/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.rs +++ b/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.rs @@ -1,6 +1,7 @@ //@ edition:2018 //@ aux-build: remove-extern-crate.rs //@ run-rustfix +//@ rustfix-only-machine-applicable #![warn(rust_2018_idioms)] diff --git a/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.stderr b/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.stderr index 632ecd623221..fc6afa500cda 100644 --- a/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.stderr +++ b/tests/ui/rust-2018/removing-extern-crate-malformed-cfg.stderr @@ -1,29 +1,33 @@ error: expected identifier, found `"macro_use"` - --> $DIR/removing-extern-crate-malformed-cfg.rs:7:18 + --> $DIR/removing-extern-crate-malformed-cfg.rs:8:18 | LL | #[cfg_attr(test, "macro_use")] - | ^^^^^^^^^^^ expected identifier + | -----------------^^^^^^^^^^^-- + | | | + | | expected identifier + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | - = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` = note: for more information, visit error: expected one of `(`, `,`, `::`, or `=`, found `` - --> $DIR/removing-extern-crate-malformed-cfg.rs:12:16 + --> $DIR/removing-extern-crate-malformed-cfg.rs:13:16 | LL | #[cfg_attr(test)] - | ^^^^ expected one of `(`, `,`, `::`, or `=` + | -----------^^^^-- + | | | + | | expected one of `(`, `,`, `::`, or `=` + | help: must be of the form: `#[cfg_attr(predicate, attr1, attr2, ...)]` | - = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` = note: for more information, visit warning: unused extern crate - --> $DIR/removing-extern-crate-malformed-cfg.rs:8:1 + --> $DIR/removing-extern-crate-malformed-cfg.rs:9:1 | LL | extern crate remove_extern_crate as foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused | note: the lint level is defined here - --> $DIR/removing-extern-crate-malformed-cfg.rs:5:9 + --> $DIR/removing-extern-crate-malformed-cfg.rs:6:9 | LL | #![warn(rust_2018_idioms)] | ^^^^^^^^^^^^^^^^ @@ -36,7 +40,7 @@ LL + | warning: unused extern crate - --> $DIR/removing-extern-crate-malformed-cfg.rs:9:1 + --> $DIR/removing-extern-crate-malformed-cfg.rs:10:1 | LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ unused @@ -48,7 +52,7 @@ LL + | warning: unused extern crate - --> $DIR/removing-extern-crate-malformed-cfg.rs:13:5 + --> $DIR/removing-extern-crate-malformed-cfg.rs:14:5 | LL | extern crate remove_extern_crate as foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unused @@ -61,7 +65,7 @@ LL + | warning: unused extern crate - --> $DIR/removing-extern-crate-malformed-cfg.rs:14:5 + --> $DIR/removing-extern-crate-malformed-cfg.rs:15:5 | LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ unused From c4dc39be0505ef6eae4cea0d337bbe0b25593fa4 Mon Sep 17 00:00:00 2001 From: Evan Jones Date: Thu, 16 Oct 2025 09:07:57 -0400 Subject: [PATCH 06/14] add link to Builder (code review improvement) --- library/std/src/thread/mod.rs | 4 ++-- library/std/src/thread/scoped.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 78c85c0af644..16313da8e178 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -620,8 +620,8 @@ impl Builder { /// (It is the responsibility of the program to either eventually join threads it /// creates or detach them; otherwise, a resource leak will result.) /// -/// This function creates a thread with the default parameters. To specify the -/// new thread's stack size or the name, use [`Builder::spawn`]. +/// This function creates a thread with the default parameters of [`Builder`]. +/// To specify the new thread's stack size or the name, use [`Builder::spawn`]. /// /// As you can see in the signature of `spawn` there are two constraints on /// both the closure given to `spawn` and its return value, let's explain them: diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs index 2368ce4988d8..75a5303fc321 100644 --- a/library/std/src/thread/scoped.rs +++ b/library/std/src/thread/scoped.rs @@ -181,8 +181,8 @@ impl<'scope, 'env> Scope<'scope, 'env> { /// end of the scope. In that case, if the spawned thread panics, [`scope`] will /// panic after all threads are joined. /// - /// This function creates a thread with the default parameters. To specify the - /// new thread's stack size or the name, use [`Builder::spawn_scoped`]. + /// This function creates a thread with the default parameters of [`Builder`]. + /// To specify the new thread's stack size or the name, use [`Builder::spawn_scoped`]. /// /// # Panics /// From 10a533417bf30c395f8355bbe9e1b1a10511b559 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Tue, 17 Jun 2025 14:49:53 -0400 Subject: [PATCH 07/14] bootstrap: migrate to object 0.37 I noticed we had a mix of 0.37 and 0.36 at work, and this was why. As far as I can tell everything still works fine. --- src/bootstrap/Cargo.lock | 4 ++-- src/bootstrap/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index fe832652d25c..5a2adb206b85 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -491,9 +491,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.5" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 9a76a7dda2ac..e1725db60cfc 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -41,7 +41,7 @@ clap_complete = "4.4" home = "0.5" ignore = "0.4" libc = "0.2" -object = { version = "0.36.3", default-features = false, features = ["archive", "coff", "read_core", "std", "unaligned"] } +object = { version = "0.37", default-features = false, features = ["archive", "coff", "read_core", "std", "unaligned"] } opener = "0.8" semver = "1.0" serde = "1.0" From fcc47d07a3bbe65450d212fadc044131fd292309 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Oct 2025 14:44:59 +0200 Subject: [PATCH 08/14] rustdoc: Fix passes order so intra-doc links are collected after stripping passes --- src/librustdoc/passes/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index f45df8d2d0d5..856581e0d033 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -94,11 +94,11 @@ pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[ ConditionalPass::always(COLLECT_TRAIT_IMPLS), ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY), ConditionalPass::always(CHECK_DOC_CFG), - ConditionalPass::always(COLLECT_INTRA_DOC_LINKS), ConditionalPass::always(STRIP_ALIASED_NON_LOCAL), ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate), ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate), + ConditionalPass::always(COLLECT_INTRA_DOC_LINKS), ConditionalPass::always(PROPAGATE_DOC_CFG), ConditionalPass::always(PROPAGATE_STABILITY), ConditionalPass::always(RUN_LINTS), From e67d502d4e813da278ac5f3696d873598ea8a16b Mon Sep 17 00:00:00 2001 From: Osama Abdelkader Date: Fri, 17 Oct 2025 00:33:45 +0300 Subject: [PATCH 09/14] Fix autodiff incorrectly applying fat-lto to proc-macro crates When -Z autodiff=Enable is used, the compiler automatically enables fat-lto for all crates. However, proc-macro crates cannot use fat-lto without the -Zdylib-lto flag, causing compilation errors. This commit modifies the lto() method in Session to exclude proc-macro crates from fat-lto when autodiff is enabled, while preserving the existing behavior for all other crate types. The fix ensures that: - Non-proc-macro crates still get fat-lto when autodiff is enabled - Proc-macro crates are excluded from fat-lto when autodiff is enabled - Existing autodiff functionality remains unchanged for regular crates Signed-off-by: Osama Abdelkader --- compiler/rustc_session/src/session.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 172672a80fbd..085983c52326 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -603,7 +603,8 @@ impl Session { // Autodiff currently requires fat-lto to have access to the llvm-ir of all (indirectly) used functions and types. // fat-lto is the easiest solution to this requirement, but quite expensive. // FIXME(autodiff): Make autodiff also work with embed-bc instead of fat-lto. - if self.opts.autodiff_enabled() { + // Don't apply fat-lto to proc-macro crates as they cannot use fat-lto without -Zdylib-lto + if self.opts.autodiff_enabled() && !self.opts.crate_types.contains(&CrateType::ProcMacro) { return config::Lto::Fat; } From b3bb7500b6ae0c47ec5f62ba3d104ec4f6f1f5e0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 17 Oct 2025 14:45:09 +0200 Subject: [PATCH 10/14] Add regression tests for intra-doc links --- tests/rustdoc-ui/intra-doc/hidden-check.rs | 14 ++++++++++++++ tests/rustdoc-ui/intra-doc/hidden-check.stderr | 14 ++++++++++++++ tests/rustdoc-ui/intra-doc/private-check.rs | 14 ++++++++++++++ tests/rustdoc-ui/intra-doc/private-check.stderr | 14 ++++++++++++++ tests/rustdoc-ui/issues/issue-91713.stdout | 2 +- 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 tests/rustdoc-ui/intra-doc/hidden-check.rs create mode 100644 tests/rustdoc-ui/intra-doc/hidden-check.stderr create mode 100644 tests/rustdoc-ui/intra-doc/private-check.rs create mode 100644 tests/rustdoc-ui/intra-doc/private-check.stderr diff --git a/tests/rustdoc-ui/intra-doc/hidden-check.rs b/tests/rustdoc-ui/intra-doc/hidden-check.rs new file mode 100644 index 000000000000..db2a6dd1dbda --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/hidden-check.rs @@ -0,0 +1,14 @@ +// This test ensures that `doc(hidden)` items intra-doc links are checked whereas private +// items are ignored. + +//@ compile-flags: -Zunstable-options --document-hidden-items + +#![deny(rustdoc::broken_intra_doc_links)] + +/// [not::exist] +//~^ ERROR unresolved link to `not::exist` +#[doc(hidden)] +pub struct X; + +/// [not::exist] +struct Y; diff --git a/tests/rustdoc-ui/intra-doc/hidden-check.stderr b/tests/rustdoc-ui/intra-doc/hidden-check.stderr new file mode 100644 index 000000000000..4fffb8010640 --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/hidden-check.stderr @@ -0,0 +1,14 @@ +error: unresolved link to `not::exist` + --> $DIR/hidden-check.rs:8:6 + | +LL | /// [not::exist] + | ^^^^^^^^^^ no item named `not` in scope + | +note: the lint level is defined here + --> $DIR/hidden-check.rs:6:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/rustdoc-ui/intra-doc/private-check.rs b/tests/rustdoc-ui/intra-doc/private-check.rs new file mode 100644 index 000000000000..2f987d1a44cf --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/private-check.rs @@ -0,0 +1,14 @@ +// This test ensures that private items intra-doc links are checked whereas `doc(hidden)` +// items are ignored. + +//@ compile-flags: -Zunstable-options --document-private-items + +#![deny(rustdoc::broken_intra_doc_links)] + +/// [not::exist] +#[doc(hidden)] +pub struct X; + +/// [not::exist] +//~^ ERROR unresolved link to `not::exist` +struct Y; diff --git a/tests/rustdoc-ui/intra-doc/private-check.stderr b/tests/rustdoc-ui/intra-doc/private-check.stderr new file mode 100644 index 000000000000..2ec162809eae --- /dev/null +++ b/tests/rustdoc-ui/intra-doc/private-check.stderr @@ -0,0 +1,14 @@ +error: unresolved link to `not::exist` + --> $DIR/private-check.rs:12:6 + | +LL | /// [not::exist] + | ^^^^^^^^^^ no item named `not` in scope + | +note: the lint level is defined here + --> $DIR/private-check.rs:6:9 + | +LL | #![deny(rustdoc::broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/rustdoc-ui/issues/issue-91713.stdout b/tests/rustdoc-ui/issues/issue-91713.stdout index d34714be6c94..7254708157f0 100644 --- a/tests/rustdoc-ui/issues/issue-91713.stdout +++ b/tests/rustdoc-ui/issues/issue-91713.stdout @@ -16,11 +16,11 @@ Default passes for rustdoc: collect-trait-impls check_doc_test_visibility check-doc-cfg -collect-intra-doc-links strip-aliased-non-local strip-hidden (when not --document-hidden-items) strip-private (when not --document-private-items) strip-priv-imports (when --document-private-items) +collect-intra-doc-links propagate-doc-cfg propagate-stability run-lints From 29a19f84c2ad86f6f524f8012a7f2b756d7677f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Sep 2025 16:58:40 +0200 Subject: [PATCH 11/14] Result/Option layout guarantee clarifications --- library/core/src/option.rs | 7 +++++-- library/core/src/result.rs | 18 ++++++++++++------ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 430ee3470ac3..47c554d75edb 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -119,8 +119,11 @@ //! # Representation //! //! Rust guarantees to optimize the following types `T` such that -//! [`Option`] has the same size, alignment, and [function call ABI] as `T`. In some -//! of these cases, Rust further guarantees the following: +//! [`Option`] has the same size, alignment, and [function call ABI] as `T`. +//! It is therefore sound to transmute `t: T` to `Option` (which will produce `Some(t)`), and +//! to transmute `Some(t): Option` to `T` (which will produce `t`). +//! +//! In some of these cases, Rust further guarantees the following: //! - `transmute::<_, Option>([0u8; size_of::()])` is sound and produces //! `Option::::None` //! - `transmute::<_, [u8; size_of::()]>(Option::::None)` is sound and produces diff --git a/library/core/src/result.rs b/library/core/src/result.rs index c69762a72859..324f288594b1 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -230,24 +230,30 @@ //! //! # Representation //! -//! In some cases, [`Result`] will gain the same size, alignment, and ABI -//! guarantees as [`Option`] has. One of either the `T` or `E` type must be a -//! type that qualifies for the `Option` [representation guarantees][opt-rep], -//! and the *other* type must meet all of the following conditions: +//! In some cases, [`Result`] comes with size, alignment, and ABI guarantees. +//! Specifically, one of either the `T` or `E` type must be a type that qualifies for the `Option` +//! [representation guarantees][opt-rep] (let's call that type `I`), and the *other* type must meet +//! all of the following conditions: //! * Is a zero-sized type with alignment 1 (a "1-ZST"). //! * Has no fields. //! * Does not have the `#[non_exhaustive]` attribute. //! +//! If that is the case, then `Result` has the same size, alignment, and [function call ABI] +//! as `I` (and therefore, as `Option`). If `I` is `T`, it is therefore sound to transmute `t: I` +//! to `Result` (which will produce `Ok(t)`), and to transmute `Ok(t): Result` to `I` +//! (which will produce `t`). If `I` is `E`, the same applies with `Ok` replaced by `Err`. +//! //! For example, `NonZeroI32` qualifies for the `Option` representation //! guarantees, and `()` is a zero-sized type with alignment 1, no fields, and //! it isn't `non_exhaustive`. This means that both `Result` and -//! `Result<(), NonZeroI32>` have the same size, alignment, and ABI guarantees -//! as `Option`. The only difference is the implied semantics: +//! `Result<(), NonZeroI32>` have the same size, alignment, and ABI +//! as `NonZeroI32` (and `Option`). The only difference is the implied semantics: //! * `Option` is "a non-zero i32 might be present" //! * `Result` is "a non-zero i32 success result, if any" //! * `Result<(), NonZeroI32>` is "a non-zero i32 error result, if any" //! //! [opt-rep]: ../option/index.html#representation "Option Representation" +//! [function call ABI]: ../primitive.fn.html#abi-compatibility //! //! # Method overview //! From 781432e355cda386ce7c394a728cd4704d78fbc5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Sep 2025 17:23:29 +0200 Subject: [PATCH 12/14] clarify 'no fields' --- compiler/rustc_lint/src/types.rs | 4 ++-- library/core/src/result.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index eaec0c9857d2..7c6655926958 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -814,7 +814,7 @@ fn get_nullable_type<'tcx>( /// A type is niche-optimization candidate iff: /// - Is a zero-sized type with alignment 1 (a “1-ZST”). -/// - Has no fields. +/// - Is either a struct/tuple with no fields, or an enum with no variants. /// - Does not have the `#[non_exhaustive]` attribute. fn is_niche_optimization_candidate<'tcx>( tcx: TyCtxt<'tcx>, @@ -828,7 +828,7 @@ fn is_niche_optimization_candidate<'tcx>( match ty.kind() { ty::Adt(ty_def, _) => { let non_exhaustive = ty_def.is_variant_list_non_exhaustive(); - let empty = (ty_def.is_struct() && ty_def.all_fields().next().is_none()) + let empty = (ty_def.is_struct() && ty_def.non_enum_variant().fields.is_empty()) || (ty_def.is_enum() && ty_def.variants().is_empty()); !non_exhaustive && empty diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 324f288594b1..86602b620004 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -235,7 +235,7 @@ //! [representation guarantees][opt-rep] (let's call that type `I`), and the *other* type must meet //! all of the following conditions: //! * Is a zero-sized type with alignment 1 (a "1-ZST"). -//! * Has no fields. +//! * Is either a struct/tuple with no fields, or an enum with no variants. //! * Does not have the `#[non_exhaustive]` attribute. //! //! If that is the case, then `Result` has the same size, alignment, and [function call ABI] From 058f08dd7835ef2f16b8a7b5389c361dbdf6bc4c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Sep 2025 21:05:30 +0200 Subject: [PATCH 13/14] have Result docs match ABI docs --- library/core/src/result.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 86602b620004..39689e657a58 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -232,20 +232,16 @@ //! //! In some cases, [`Result`] comes with size, alignment, and ABI guarantees. //! Specifically, one of either the `T` or `E` type must be a type that qualifies for the `Option` -//! [representation guarantees][opt-rep] (let's call that type `I`), and the *other* type must meet -//! all of the following conditions: -//! * Is a zero-sized type with alignment 1 (a "1-ZST"). -//! * Is either a struct/tuple with no fields, or an enum with no variants. -//! * Does not have the `#[non_exhaustive]` attribute. +//! [representation guarantees][opt-rep] (let's call that type `I`), and the *other* type +//! is a zero-sized type with alignment 1 (a "1-ZST"). //! //! If that is the case, then `Result` has the same size, alignment, and [function call ABI] //! as `I` (and therefore, as `Option`). If `I` is `T`, it is therefore sound to transmute `t: I` //! to `Result` (which will produce `Ok(t)`), and to transmute `Ok(t): Result` to `I` //! (which will produce `t`). If `I` is `E`, the same applies with `Ok` replaced by `Err`. //! -//! For example, `NonZeroI32` qualifies for the `Option` representation -//! guarantees, and `()` is a zero-sized type with alignment 1, no fields, and -//! it isn't `non_exhaustive`. This means that both `Result` and +//! For example, `NonZeroI32` qualifies for the `Option` representation guarantees, and `()` is a +//! zero-sized type with alignment 1. This means that both `Result` and //! `Result<(), NonZeroI32>` have the same size, alignment, and ABI //! as `NonZeroI32` (and `Option`). The only difference is the implied semantics: //! * `Option` is "a non-zero i32 might be present" From 73f5fe78d4b822124ca6082d49592314eb9d68a9 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sat, 18 Oct 2025 00:23:15 +0000 Subject: [PATCH 14/14] Revise `Result`/`Option` guarantee docs The notation used here (e.g. "transmute `t: T` to `Option`") felt maybe a bit heavy, in the context of the library documentation, so let's elaborate this a bit. Also, in the `Option` docs, we talk about this being true for "the following types `T`", but it felt this caveat might get a bit lost in the next sentence that talks about the valid transmutations, so let's reiterate the caveat. While we're touching the line, we can improve: > The only difference is the implied semantics: This sentence was a bit awkward due to the mismatched plurality and not identifying the difference being spoken to. We'll reword this to make it more clear. We'll wrap to 80, since the existing text and most of the doc comments in these files are wrapped this way. --- library/core/src/option.rs | 10 ++++++---- library/core/src/result.rs | 29 +++++++++++++++++------------ 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 47c554d75edb..e3c4758bc6af 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -118,10 +118,12 @@ //! //! # Representation //! -//! Rust guarantees to optimize the following types `T` such that -//! [`Option`] has the same size, alignment, and [function call ABI] as `T`. -//! It is therefore sound to transmute `t: T` to `Option` (which will produce `Some(t)`), and -//! to transmute `Some(t): Option` to `T` (which will produce `t`). +//! Rust guarantees to optimize the following types `T` such that [`Option`] +//! has the same size, alignment, and [function call ABI] as `T`. It is +//! therefore sound, when `T` is one of these types, to transmute a value `t` of +//! type `T` to type `Option` (producing the value `Some(t)`) and to +//! transmute a value `Some(t)` of type `Option` to type `T` (producing the +//! value `t`). //! //! In some of these cases, Rust further guarantees the following: //! - `transmute::<_, Option>([0u8; size_of::()])` is sound and produces diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 39689e657a58..6fee7febde38 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -230,20 +230,25 @@ //! //! # Representation //! -//! In some cases, [`Result`] comes with size, alignment, and ABI guarantees. -//! Specifically, one of either the `T` or `E` type must be a type that qualifies for the `Option` -//! [representation guarantees][opt-rep] (let's call that type `I`), and the *other* type -//! is a zero-sized type with alignment 1 (a "1-ZST"). +//! In some cases, [`Result`] comes with size, alignment, and ABI +//! guarantees. Specifically, one of either the `T` or `E` type must be a type +//! that qualifies for the `Option` [representation guarantees][opt-rep] (let's +//! call that type `I`), and the *other* type is a zero-sized type with +//! alignment 1 (a "1-ZST"). //! -//! If that is the case, then `Result` has the same size, alignment, and [function call ABI] -//! as `I` (and therefore, as `Option`). If `I` is `T`, it is therefore sound to transmute `t: I` -//! to `Result` (which will produce `Ok(t)`), and to transmute `Ok(t): Result` to `I` -//! (which will produce `t`). If `I` is `E`, the same applies with `Ok` replaced by `Err`. +//! If that is the case, then `Result` has the same size, alignment, and +//! [function call ABI] as `I` (and therefore, as `Option`). If `I` is `T`, +//! it is therefore sound to transmute a value `t` of type `I` to type +//! `Result` (producing the value `Ok(t)`) and to transmute a value +//! `Ok(t)` of type `Result` to type `I` (producing the value `t`). If `I` +//! is `E`, the same applies with `Ok` replaced by `Err`. +//! +//! For example, `NonZeroI32` qualifies for the `Option` representation +//! guarantees and `()` is a zero-sized type with alignment 1. This means that +//! both `Result` and `Result<(), NonZeroI32>` have the same +//! size, alignment, and ABI as `NonZeroI32` (and `Option`). The +//! only difference between these is in the implied semantics: //! -//! For example, `NonZeroI32` qualifies for the `Option` representation guarantees, and `()` is a -//! zero-sized type with alignment 1. This means that both `Result` and -//! `Result<(), NonZeroI32>` have the same size, alignment, and ABI -//! as `NonZeroI32` (and `Option`). The only difference is the implied semantics: //! * `Option` is "a non-zero i32 might be present" //! * `Result` is "a non-zero i32 success result, if any" //! * `Result<(), NonZeroI32>` is "a non-zero i32 error result, if any"