diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 61f816f0baf8f..fb9016ca4d86e 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -50,11 +50,6 @@ attr_parsing_expects_feature_list = attr_parsing_expects_features = `{$name}` expects feature names -attr_parsing_ill_formed_attribute_input = {$num_suggestions -> - [1] attribute must be of the form {$suggestions} - *[other] valid forms for the attribute are {$suggestions} - } - attr_parsing_import_name_type_raw = import name type can only be used with link kind `raw-dylib` @@ -213,10 +208,6 @@ attr_parsing_stability_outside_std = stability attributes may not be used outsid attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes .help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) -attr_parsing_unknown_meta_item = - unknown meta item '{$item}' - .label = expected one of {$expected} - attr_parsing_unknown_version_literal = unknown version literal format, assuming it refers to a future version diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index 5b4786a64ef2d..798cc10765415 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -42,7 +42,7 @@ pub fn parse_cfg( args: &ArgParser, ) -> Option { let ArgParser::List(list) = args else { - cx.expected_list(cx.attr_span); + cx.expected_list(cx.attr_span, args); return None; }; let Some(single) = list.single() else { diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 05da89167778e..1ace3bf7cbf90 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -25,7 +25,7 @@ impl SingleAttributeParser for OptimizeParser { fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(list) = args.list() else { - cx.expected_list(cx.attr_span); + cx.expected_list(cx.attr_span, args); return None; }; @@ -478,7 +478,7 @@ fn parse_tf_attribute( ) -> impl IntoIterator { let mut features = Vec::new(); let ArgParser::List(list) = args else { - cx.expected_list(cx.attr_span); + cx.expected_list(cx.attr_span, args); return features; }; if list.is_empty() { @@ -601,7 +601,7 @@ impl SingleAttributeParser for SanitizeParser { fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(list) = args.list() else { - cx.expected_list(cx.attr_span); + cx.expected_list(cx.attr_span, args); return None; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index 97e78dfb136b9..0b7ac989346a4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -13,7 +13,7 @@ impl AttributeParser for ConfusablesParser { template!(List: &[r#""name1", "name2", ..."#]), |this, cx, args| { let Some(list) = args.list() else { - cx.expected_list(cx.attr_span); + cx.expected_list(cx.attr_span, args); return; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/debugger.rs b/compiler/rustc_attr_parsing/src/attributes/debugger.rs index c88b795aab03d..52a66942cf939 100644 --- a/compiler/rustc_attr_parsing/src/attributes/debugger.rs +++ b/compiler/rustc_attr_parsing/src/attributes/debugger.rs @@ -21,7 +21,7 @@ impl CombineAttributeParser for DebuggerViualizerParser { args: &ArgParser, ) -> impl IntoIterator { let Some(l) = args.list() else { - cx.expected_list(args.span().unwrap_or(cx.attr_span)); + cx.expected_list(cx.attr_span, args); return None; }; let Some(single) = l.single() else { diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index ad3e2ced60c7d..2d79e3a103d6e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -110,13 +110,12 @@ impl SingleAttributeParser for DeprecationParser { Some(get(cx, name, param.span(), param.args(), &suggestion)?); } _ => { - cx.unknown_key( + cx.expected_specific_argument( param.span(), - param.path().to_string(), if features.deprecated_suggestion() { - &["since", "note", "suggestion"] + &[sym::since, sym::note, sym::suggestion] } else { - &["since", "note"] + &[sym::since, sym::note] }, ); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index b6fea37c92aa2..16dbb04b48ebd 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -106,7 +106,7 @@ impl DocParser { } Some(sym::attr) => { let Some(list) = args.list() else { - cx.expected_list(cx.attr_span); + cx.expected_list(cx.attr_span, args); return; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index fe8f3578fe145..388553c8fd9b6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -76,7 +76,7 @@ impl CombineAttributeParser for LinkParser { return None; } _ => { - cx.expected_list(cx.attr_span); + cx.expected_list(cx.attr_span, args); return None; } }; @@ -379,7 +379,7 @@ impl LinkParser { return true; } let Some(link_cfg) = item.args().list() else { - cx.expected_list(item.span()); + cx.expected_list(item.span(), item.args()); return true; }; let Some(link_cfg) = link_cfg.single() else { diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index e4209c3edd85c..0f1ab02fca251 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -1,9 +1,7 @@ -use rustc_errors::DiagArgValue; use rustc_hir::attrs::MacroUseArgs; use rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS; use super::prelude::*; -use crate::session_diagnostics::IllFormedAttributeInputLint; pub(crate) struct MacroEscapeParser; impl NoArgsAttributeParser for MacroEscapeParser { @@ -101,15 +99,8 @@ impl AttributeParser for MacroUseParser { } } } - ArgParser::NameValue(_) => { - let suggestions = cx.suggestions(); - cx.emit_err(IllFormedAttributeInputLint { - num_suggestions: suggestions.len(), - suggestions: DiagArgValue::StrListSepByAnd( - suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), - ), - span, - }); + ArgParser::NameValue(nv) => { + cx.expected_list_or_no_args(nv.args_span()); } } }, @@ -164,16 +155,8 @@ impl SingleAttributeParser for MacroExportParser { } } } - ArgParser::NameValue(_) => { - let span = cx.attr_span; - let suggestions = cx.suggestions(); - cx.emit_err(IllFormedAttributeInputLint { - num_suggestions: suggestions.len(), - suggestions: DiagArgValue::StrListSepByAnd( - suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), - ), - span, - }); + ArgParser::NameValue(nv) => { + cx.expected_list_or_no_args(nv.args_span()); return None; } }; diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs index a27e1ecb707e3..673e2c902da0b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -1,7 +1,4 @@ -use rustc_errors::DiagArgValue; - use super::prelude::*; -use crate::session_diagnostics::IllFormedAttributeInputLint; pub(crate) struct MustUseParser; @@ -44,15 +41,8 @@ impl SingleAttributeParser for MustUseParser { }; Some(value_str) } - ArgParser::List(_) => { - let suggestions = cx.suggestions(); - cx.emit_err(IllFormedAttributeInputLint { - num_suggestions: suggestions.len(), - suggestions: DiagArgValue::StrListSepByAnd( - suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), - ), - span: cx.attr_span, - }); + ArgParser::List(list) => { + cx.expected_nv_or_no_args(list.span); return None; } }, diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index e1762005d4c4a..3674aa7124abb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -65,7 +65,7 @@ fn parse_derive_like( if args.no_args().is_ok() && !trait_name_mandatory { return Some((None, ThinVec::new())); } - cx.expected_list(cx.attr_span); + cx.expected_list(cx.attr_span, args); return None; }; let mut items = list.mixed(); @@ -96,7 +96,7 @@ fn parse_derive_like( let mut attributes = ThinVec::new(); if let Some(attrs) = items.next() { let Some(attr_list) = attrs.meta_item() else { - cx.expected_list(attrs.span()); + cx.unexpected_literal(attrs.span()); return None; }; if !attr_list.path().word_is(sym::attributes) { @@ -104,7 +104,7 @@ fn parse_derive_like( return None; } let Some(attr_list) = attr_list.args().list() else { - cx.expected_list(attrs.span()); + cx.expected_list(attrs.span(), attr_list.args()); return None; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs index cd7c84f45fe51..ac50fe33839d2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prototype.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs @@ -27,7 +27,7 @@ impl SingleAttributeParser for CustomMirParser { fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { let Some(list) = args.list() else { - cx.expected_list(cx.attr_span); + cx.expected_list(cx.attr_span, args); return None; }; @@ -46,9 +46,8 @@ impl SingleAttributeParser for CustomMirParser { extract_value(cx, sym::dialect, arg, meta_item.span(), &mut dialect, &mut failed); } else if let Some(arg) = meta_item.word_is(sym::phase) { extract_value(cx, sym::phase, arg, meta_item.span(), &mut phase, &mut failed); - } else if let Some(word) = meta_item.path().word() { - let word = word.to_string(); - cx.unknown_key(meta_item.span(), word, &["dialect", "phase"]); + } else if let Some(..) = meta_item.path().word() { + cx.expected_specific_argument(meta_item.span(), &[sym::dialect, sym::phase]); failed = true; } else { cx.expected_name_value(meta_item.span(), None); diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 4520e4f5dbac1..9ad103f3bb8ee 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -33,7 +33,7 @@ impl CombineAttributeParser for ReprParser { let mut reprs = Vec::new(); let Some(list) = args.list() else { - cx.expected_list(cx.attr_span); + cx.expected_list(cx.attr_span, args); return reprs; }; @@ -278,7 +278,7 @@ impl AlignParser { fn parse(&mut self, cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) { match args { ArgParser::NoArgs | ArgParser::NameValue(_) => { - cx.expected_list(cx.attr_span); + cx.expected_list(cx.attr_span, args); } ArgParser::List(list) => { let Some(align) = list.single() else { diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 571cb884c1fcd..6d4f77ef1751b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -295,7 +295,7 @@ pub(crate) fn parse_stability( let mut since = None; let ArgParser::List(list) = args else { - cx.expected_list(cx.attr_span); + cx.expected_list(cx.attr_span, args); return None; }; @@ -315,11 +315,7 @@ pub(crate) fn parse_stability( insert_value_into_option_or_error(cx, ¶m, &mut since, word.unwrap())? } _ => { - cx.emit_err(session_diagnostics::UnknownMetaItem { - span: param_span, - item: param.path().to_string(), - expected: &["feature", "since"], - }); + cx.expected_specific_argument(param_span, &[sym::feature, sym::since]); return None; } } @@ -371,7 +367,7 @@ pub(crate) fn parse_unstability( let mut old_name = None; let ArgParser::List(list) = args else { - cx.expected_list(cx.attr_span); + cx.expected_list(cx.attr_span, args); return None; }; @@ -426,11 +422,17 @@ pub(crate) fn parse_unstability( insert_value_into_option_or_error(cx, ¶m, &mut old_name, word.unwrap())? } _ => { - cx.emit_err(session_diagnostics::UnknownMetaItem { - span: param.span(), - item: param.path().to_string(), - expected: &["feature", "reason", "issue", "soft", "implied_by", "old_name"], - }); + cx.expected_specific_argument( + param.span(), + &[ + sym::feature, + sym::reason, + sym::issue, + sym::soft, + sym::implied_by, + sym::old_name, + ], + ); return None; } } diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index a9b76021a989d..ee5895a6efd0f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -22,7 +22,7 @@ impl SingleAttributeParser for SkipDuringMethodDispatchParser { let mut array = false; let mut boxed_slice = false; let Some(args) = args.list() else { - cx.expected_list(cx.attr_span); + cx.expected_list(cx.attr_span, args); return None; }; if args.is_empty() { diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 4e3478abbf4fd..431ba539b2ba2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -43,7 +43,7 @@ pub(crate) fn parse_single_integer( args: &ArgParser, ) -> Option { let Some(list) = args.list() else { - cx.expected_list(cx.attr_span); + cx.expected_list(cx.attr_span, args); return None; }; let Some(single) = list.single() else { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index e5cabd4f71424..8f5f5c55dcd59 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -77,7 +77,7 @@ use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; use crate::parser::{ArgParser, RefPathParser}; use crate::session_diagnostics::{ - AttributeParseError, AttributeParseErrorReason, ParsedDescription, UnknownMetaItem, + AttributeParseError, AttributeParseErrorReason, ParsedDescription, }; use crate::target_checking::AllowedTargets; @@ -426,13 +426,20 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> { } impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { - pub(crate) fn unknown_key( + fn emit_parse_error( &self, span: Span, - found: String, - options: &[&'static str], + reason: AttributeParseErrorReason<'_>, ) -> ErrorGuaranteed { - self.emit_err(UnknownMetaItem { span, item: found, expected: options }) + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + path: self.attr_path.clone(), + description: self.parsed_description, + reason, + suggestions: self.suggestions(), + }) } /// error that a string literal was expected. @@ -444,133 +451,69 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { span: Span, actual_literal: Option<&MetaItemLit>, ) -> ErrorGuaranteed { - self.emit_err(AttributeParseError { + self.emit_parse_error( span, - attr_span: self.attr_span, - template: self.template.clone(), - path: self.attr_path.clone(), - description: self.parsed_description, - reason: AttributeParseErrorReason::ExpectedStringLiteral { + AttributeParseErrorReason::ExpectedStringLiteral { byte_string: actual_literal.and_then(|i| { i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span)) }), }, - suggestions: self.suggestions(), - }) + ) } pub(crate) fn expected_integer_literal(&self, span: Span) -> ErrorGuaranteed { - self.emit_err(AttributeParseError { - span, - attr_span: self.attr_span, - template: self.template.clone(), - path: self.attr_path.clone(), - description: self.parsed_description, - reason: AttributeParseErrorReason::ExpectedIntegerLiteral, - suggestions: self.suggestions(), - }) + self.emit_parse_error(span, AttributeParseErrorReason::ExpectedIntegerLiteral) } - pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed { - self.emit_err(AttributeParseError { - span, - attr_span: self.attr_span, - template: self.template.clone(), - path: self.attr_path.clone(), - description: self.parsed_description, - reason: AttributeParseErrorReason::ExpectedList, - suggestions: self.suggestions(), - }) + pub(crate) fn expected_list(&self, span: Span, args: &ArgParser) -> ErrorGuaranteed { + let span = match args { + ArgParser::NoArgs => span, + ArgParser::List(list) => list.span, + ArgParser::NameValue(nv) => nv.args_span(), + }; + self.emit_parse_error(span, AttributeParseErrorReason::ExpectedList) } - pub(crate) fn expected_no_args(&self, args_span: Span) -> ErrorGuaranteed { - self.emit_err(AttributeParseError { - span: args_span, - attr_span: self.attr_span, - template: self.template.clone(), - path: self.attr_path.clone(), - description: self.parsed_description, - reason: AttributeParseErrorReason::ExpectedNoArgs, - suggestions: self.suggestions(), - }) + pub(crate) fn expected_list_or_no_args(&self, span: Span) -> ErrorGuaranteed { + self.emit_parse_error(span, AttributeParseErrorReason::ExpectedListOrNoArgs) + } + + pub(crate) fn expected_nv_or_no_args(&self, span: Span) -> ErrorGuaranteed { + self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNameValueOrNoArgs) + } + + pub(crate) fn expected_no_args(&self, span: Span) -> ErrorGuaranteed { + self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNoArgs) } /// emit an error that a `name` was expected here pub(crate) fn expected_identifier(&self, span: Span) -> ErrorGuaranteed { - self.emit_err(AttributeParseError { - span, - attr_span: self.attr_span, - template: self.template.clone(), - path: self.attr_path.clone(), - description: self.parsed_description, - reason: AttributeParseErrorReason::ExpectedIdentifier, - suggestions: self.suggestions(), - }) + self.emit_parse_error(span, AttributeParseErrorReason::ExpectedIdentifier) } /// emit an error that a `name = value` pair was expected at this span. The symbol can be given for /// a nicer error message talking about the specific name that was found lacking a value. pub(crate) fn expected_name_value(&self, span: Span, name: Option) -> ErrorGuaranteed { - self.emit_err(AttributeParseError { - span, - attr_span: self.attr_span, - template: self.template.clone(), - path: self.attr_path.clone(), - description: self.parsed_description, - reason: AttributeParseErrorReason::ExpectedNameValue(name), - suggestions: self.suggestions(), - }) + self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNameValue(name)) } /// emit an error that a `name = value` pair was found where that name was already seen. pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed { - self.emit_err(AttributeParseError { - span, - attr_span: self.attr_span, - template: self.template.clone(), - path: self.attr_path.clone(), - description: self.parsed_description, - reason: AttributeParseErrorReason::DuplicateKey(key), - suggestions: self.suggestions(), - }) + self.emit_parse_error(span, AttributeParseErrorReason::DuplicateKey(key)) } /// an error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser) /// was expected *not* to be a literal, but instead a meta item. pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed { - self.emit_err(AttributeParseError { - span, - attr_span: self.attr_span, - template: self.template.clone(), - path: self.attr_path.clone(), - description: self.parsed_description, - reason: AttributeParseErrorReason::UnexpectedLiteral, - suggestions: self.suggestions(), - }) + self.emit_parse_error(span, AttributeParseErrorReason::UnexpectedLiteral) } pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed { - self.emit_err(AttributeParseError { - span, - attr_span: self.attr_span, - template: self.template.clone(), - path: self.attr_path.clone(), - description: self.parsed_description, - reason: AttributeParseErrorReason::ExpectedSingleArgument, - suggestions: self.suggestions(), - }) + self.emit_parse_error(span, AttributeParseErrorReason::ExpectedSingleArgument) } pub(crate) fn expected_at_least_one_argument(&self, span: Span) -> ErrorGuaranteed { - self.emit_err(AttributeParseError { - span, - attr_span: self.attr_span, - template: self.template.clone(), - path: self.attr_path.clone(), - description: self.parsed_description, - reason: AttributeParseErrorReason::ExpectedAtLeastOneArgument, - suggestions: self.suggestions(), - }) + self.emit_parse_error(span, AttributeParseErrorReason::ExpectedAtLeastOneArgument) } /// produces an error along the lines of `expected one of [foo, meow]` @@ -579,19 +522,14 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { span: Span, possibilities: &[Symbol], ) -> ErrorGuaranteed { - self.emit_err(AttributeParseError { + self.emit_parse_error( span, - attr_span: self.attr_span, - template: self.template.clone(), - path: self.attr_path.clone(), - description: self.parsed_description, - reason: AttributeParseErrorReason::ExpectedSpecificArgument { + AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings: false, list: false, }, - suggestions: self.suggestions(), - }) + ) } /// produces an error along the lines of `expected one of [foo, meow] as an argument`. @@ -601,19 +539,14 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { span: Span, possibilities: &[Symbol], ) -> ErrorGuaranteed { - self.emit_err(AttributeParseError { + self.emit_parse_error( span, - attr_span: self.attr_span, - template: self.template.clone(), - path: self.attr_path.clone(), - description: self.parsed_description, - reason: AttributeParseErrorReason::ExpectedSpecificArgument { + AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings: false, list: true, }, - suggestions: self.suggestions(), - }) + ) } /// produces an error along the lines of `expected one of ["foo", "meow"]` @@ -622,19 +555,14 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { span: Span, possibilities: &[Symbol], ) -> ErrorGuaranteed { - self.emit_err(AttributeParseError { + self.emit_parse_error( span, - attr_span: self.attr_span, - template: self.template.clone(), - path: self.attr_path.clone(), - description: self.parsed_description, - reason: AttributeParseErrorReason::ExpectedSpecificArgument { + AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings: true, list: false, }, - suggestions: self.suggestions(), - }) + ) } pub(crate) fn warn_empty_attribute(&mut self, span: Span) { diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 09ecfaedb5ed2..9551744d5ec53 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -177,7 +177,7 @@ impl ArgParser { match self { Self::NoArgs => Ok(()), Self::List(args) => Err(args.span), - Self::NameValue(args) => Err(args.eq_span.to(args.value_span)), + Self::NameValue(args) => Err(args.args_span()), } } } @@ -314,6 +314,10 @@ impl NameValueParser { pub fn value_as_str(&self) -> Option { self.value_as_lit().kind.str() } + + pub fn args_span(&self) -> Span { + self.eq_span.to(self.value_span) + } } fn expr_to_lit( diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index b50a7f92fcdc5..4aea4064b1c4b 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -64,26 +64,6 @@ pub(crate) struct DocAttributeNotAttribute { pub attribute: Symbol, } -/// Error code: E0541 -pub(crate) struct UnknownMetaItem<'a> { - pub span: Span, - pub item: String, - pub expected: &'a [&'a str], -} - -// Manual implementation to be able to format `expected` items correctly. -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnknownMetaItem<'_> { - fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { - let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::>(); - Diag::new(dcx, level, fluent::attr_parsing_unknown_meta_item) - .with_span(self.span) - .with_code(E0541) - .with_arg("item", self.item) - .with_arg("expected", expected.join(", ")) - .with_span_label(self.span, fluent::attr_parsing_label) - } -} - #[derive(Diagnostic)] #[diag(attr_parsing_missing_since, code = E0542)] pub(crate) struct MissingSince { @@ -400,15 +380,6 @@ pub(crate) struct UnusedMultiple { pub name: Symbol, } -#[derive(Diagnostic)] -#[diag(attr_parsing_ill_formed_attribute_input)] -pub(crate) struct IllFormedAttributeInputLint { - #[primary_span] - pub span: Span, - pub num_suggestions: usize, - pub suggestions: DiagArgValue, -} - #[derive(Diagnostic)] #[diag(attr_parsing_null_on_export, code = E0648)] pub(crate) struct NullOnExport { @@ -539,6 +510,8 @@ pub(crate) enum AttributeParseErrorReason<'a> { ExpectedAtLeastOneArgument, ExpectedSingleArgument, ExpectedList, + ExpectedListOrNoArgs, + ExpectedNameValueOrNoArgs, UnexpectedLiteral, ExpectedNameValue(Option), DuplicateKey(Symbol), @@ -611,6 +584,12 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> { AttributeParseErrorReason::ExpectedList => { diag.span_label(self.span, "expected this to be a list"); } + AttributeParseErrorReason::ExpectedListOrNoArgs => { + diag.span_label(self.span, "expected a list or no arguments here"); + } + AttributeParseErrorReason::ExpectedNameValueOrNoArgs => { + diag.span_label(self.span, "didn't expect a list here"); + } AttributeParseErrorReason::DuplicateKey(key) => { diag.span_label(self.span, format!("found `{key}` used as a key more than once")); diag.code(E0538); diff --git a/compiler/rustc_error_codes/src/error_codes/E0541.md b/compiler/rustc_error_codes/src/error_codes/E0541.md index 96334088feeef..f1f97b39fa282 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0541.md +++ b/compiler/rustc_error_codes/src/error_codes/E0541.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + An unknown meta item was used. Erroneous code example: -```compile_fail,E0541 +```compile_fail (no longer emitted) #[deprecated( since="1.0.0", // error: unknown meta item diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 56a0a3ceebf5a..1160bd9ffa749 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -205,15 +205,17 @@ lint_dangling_pointers_from_locals = {$fn_kind} returns a dangling pointer to dr .ret_ty = return type is `{$ret_ty}` .local_var = local variable `{$local_var_name}` is dropped at the end of the {$fn_kind} .created_at = dangling pointer created here - .note = a dangling pointer is safe, but dereferencing one is undefined behavior - -lint_dangling_pointers_from_temporaries = a dangling pointer will be produced because the temporary `{$ty}` will be dropped - .label_ptr = this pointer will immediately be invalid - .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime - .note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - .help_bind = you must make sure that the variable you bind the `{$ty}` to lives at least as long as the pointer returned by the call to `{$callee}` - .help_returned = in particular, if this pointer is returned from the current function, binding the `{$ty}` inside the function will not suffice - .help_visit = for more information, see + .note_safe = a dangling pointer is safe, but dereferencing one is undefined behavior + .note_more_info = for more information, see + +lint_dangling_pointers_from_temporaries = this creates a dangling pointer because temporary `{$ty}` is dropped at end of statement + .label_ptr = pointer created here + .label_temporary = this `{$ty}` is dropped at end of statement + .help_bind = bind the `{$ty}` to a variable such that it outlives the pointer returned by `{$callee}` + .note_safe = a dangling pointer is safe, but dereferencing one is undefined behavior + .note_return = returning a pointer to a local variable will always result in a dangling pointer + .note_more_info = for more information, see + lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 5017ce7caa525..fde9546bd1c75 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1138,10 +1138,10 @@ pub(crate) struct IgnoredUnlessCrateSpecified<'a> { // dangling.rs #[derive(LintDiagnostic)] #[diag(lint_dangling_pointers_from_temporaries)] -#[note] #[help(lint_help_bind)] -#[help(lint_help_returned)] -#[help(lint_help_visit)] +#[note(lint_note_safe)] +#[note(lint_note_return)] +#[note(lint_note_more_info)] // FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts pub(crate) struct DanglingPointersFromTemporaries<'tcx> { pub callee: Ident, @@ -1154,7 +1154,8 @@ pub(crate) struct DanglingPointersFromTemporaries<'tcx> { #[derive(LintDiagnostic)] #[diag(lint_dangling_pointers_from_locals)] -#[note] +#[note(lint_note_safe)] +#[note(lint_note_more_info)] pub(crate) struct DanglingPointersFromLocals<'tcx> { pub ret_ty: Ty<'tcx>, #[label(lint_ret_ty)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index e00cf45fcab20..1f066697fa487 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -160,11 +160,10 @@ use crate::{fmt, intrinsics, ptr, slice}; /// /// ## Initializing a struct field-by-field /// -/// You can use `MaybeUninit`, and the [`std::ptr::addr_of_mut`] macro, to initialize structs field by field: +/// You can use `MaybeUninit` and the [`&raw mut`] syntax to initialize structs field by field: /// /// ```rust /// use std::mem::MaybeUninit; -/// use std::ptr::addr_of_mut; /// /// #[derive(Debug, PartialEq)] /// pub struct Foo { @@ -179,11 +178,11 @@ use crate::{fmt, intrinsics, ptr, slice}; /// // Initializing the `name` field /// // Using `write` instead of assignment via `=` to not call `drop` on the /// // old, uninitialized value. -/// unsafe { addr_of_mut!((*ptr).name).write("Bob".to_string()); } +/// unsafe { (&raw mut (*ptr).name).write("Bob".to_string()); } /// /// // Initializing the `list` field /// // If there is a panic here, then the `String` in the `name` field leaks. -/// unsafe { addr_of_mut!((*ptr).list).write(vec![0, 1, 2]); } +/// unsafe { (&raw mut (*ptr).list).write(vec![0, 1, 2]); } /// /// // All the fields are initialized, so we call `assume_init` to get an initialized Foo. /// unsafe { uninit.assume_init() } @@ -197,7 +196,7 @@ use crate::{fmt, intrinsics, ptr, slice}; /// } /// ); /// ``` -/// [`std::ptr::addr_of_mut`]: crate::ptr::addr_of_mut +/// [`&raw mut`]: https://doc.rust-lang.org/reference/types/pointer.html#r-type.pointer.raw.constructor /// [ub]: ../../reference/behavior-considered-undefined.html /// /// # Layout diff --git a/library/std/src/io/pipe.rs b/library/std/src/io/pipe.rs index 16727d445416c..8457e7bceddca 100644 --- a/library/std/src/io/pipe.rs +++ b/library/std/src/io/pipe.rs @@ -1,5 +1,5 @@ use crate::io; -use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; +use crate::sys::pipe as imp; use crate::sys_common::{FromInner, IntoInner}; /// Creates an anonymous pipe. @@ -84,39 +84,39 @@ use crate::sys_common::{FromInner, IntoInner}; #[stable(feature = "anonymous_pipe", since = "1.87.0")] #[inline] pub fn pipe() -> io::Result<(PipeReader, PipeWriter)> { - pipe_inner().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer))) + imp::pipe().map(|(reader, writer)| (PipeReader(reader), PipeWriter(writer))) } /// Read end of an anonymous pipe. #[stable(feature = "anonymous_pipe", since = "1.87.0")] #[derive(Debug)] -pub struct PipeReader(pub(crate) AnonPipe); +pub struct PipeReader(pub(crate) imp::Pipe); /// Write end of an anonymous pipe. #[stable(feature = "anonymous_pipe", since = "1.87.0")] #[derive(Debug)] -pub struct PipeWriter(pub(crate) AnonPipe); +pub struct PipeWriter(pub(crate) imp::Pipe); -impl FromInner for PipeReader { - fn from_inner(inner: AnonPipe) -> Self { +impl FromInner for PipeReader { + fn from_inner(inner: imp::Pipe) -> Self { Self(inner) } } -impl IntoInner for PipeReader { - fn into_inner(self) -> AnonPipe { +impl IntoInner for PipeReader { + fn into_inner(self) -> imp::Pipe { self.0 } } -impl FromInner for PipeWriter { - fn from_inner(inner: AnonPipe) -> Self { +impl FromInner for PipeWriter { + fn from_inner(inner: imp::Pipe) -> Self { Self(inner) } } -impl IntoInner for PipeWriter { - fn into_inner(self) -> AnonPipe { +impl IntoInner for PipeWriter { + fn into_inner(self) -> imp::Pipe { self.0 } } diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index ee0c460f7dfa7..74b46d2975716 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -8,6 +8,7 @@ use crate::ffi::OsStr; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::path::Path; use crate::sealed::Sealed; +use crate::sys::process::ChildPipe; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::{io, process, sys}; @@ -511,7 +512,7 @@ impl From for OwnedFd { /// Takes ownership of a [`ChildStdin`](crate::process::ChildStdin)'s file descriptor. #[inline] fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd { - child_stdin.into_inner().into_inner().into_inner() + child_stdin.into_inner().into_inner() } } @@ -523,8 +524,7 @@ impl From for OwnedFd { impl From for process::ChildStdin { #[inline] fn from(fd: OwnedFd) -> process::ChildStdin { - let fd = sys::fd::FileDesc::from_inner(fd); - let pipe = sys::pipe::AnonPipe::from_inner(fd); + let pipe = ChildPipe::from_inner(fd); process::ChildStdin::from_inner(pipe) } } @@ -542,7 +542,7 @@ impl From for OwnedFd { /// Takes ownership of a [`ChildStdout`](crate::process::ChildStdout)'s file descriptor. #[inline] fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd { - child_stdout.into_inner().into_inner().into_inner() + child_stdout.into_inner().into_inner() } } @@ -554,8 +554,7 @@ impl From for OwnedFd { impl From for process::ChildStdout { #[inline] fn from(fd: OwnedFd) -> process::ChildStdout { - let fd = sys::fd::FileDesc::from_inner(fd); - let pipe = sys::pipe::AnonPipe::from_inner(fd); + let pipe = ChildPipe::from_inner(fd); process::ChildStdout::from_inner(pipe) } } @@ -573,7 +572,7 @@ impl From for OwnedFd { /// Takes ownership of a [`ChildStderr`](crate::process::ChildStderr)'s file descriptor. #[inline] fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd { - child_stderr.into_inner().into_inner().into_inner() + child_stderr.into_inner().into_inner() } } @@ -585,8 +584,7 @@ impl From for OwnedFd { impl From for process::ChildStderr { #[inline] fn from(fd: OwnedFd) -> process::ChildStderr { - let fd = sys::fd::FileDesc::from_inner(fd); - let pipe = sys::pipe::AnonPipe::from_inner(fd); + let pipe = ChildPipe::from_inner(fd); process::ChildStderr::from_inner(pipe) } } diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index f21ed51606f6d..b34b5d2802ca0 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -117,7 +117,7 @@ impl IntoRawHandle for process::ChildStderr { impl From for process::ChildStdin { fn from(handle: OwnedHandle) -> process::ChildStdin { let handle = sys::handle::Handle::from_inner(handle); - let pipe = sys::pipe::AnonPipe::from_inner(handle); + let pipe = sys::process::ChildPipe::from_inner(handle); process::ChildStdin::from_inner(pipe) } } @@ -130,7 +130,7 @@ impl From for process::ChildStdin { impl From for process::ChildStdout { fn from(handle: OwnedHandle) -> process::ChildStdout { let handle = sys::handle::Handle::from_inner(handle); - let pipe = sys::pipe::AnonPipe::from_inner(handle); + let pipe = sys::process::ChildPipe::from_inner(handle); process::ChildStdout::from_inner(pipe) } } @@ -143,7 +143,7 @@ impl From for process::ChildStdout { impl From for process::ChildStderr { fn from(handle: OwnedHandle) -> process::ChildStderr { let handle = sys::handle::Handle::from_inner(handle); - let pipe = sys::pipe::AnonPipe::from_inner(handle); + let pipe = sys::process::ChildPipe::from_inner(handle); process::ChildStderr::from_inner(pipe) } } diff --git a/library/std/src/process.rs b/library/std/src/process.rs index dbcf2684c6fb1..68bdf04d08b39 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -166,7 +166,6 @@ use crate::io::prelude::*; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::num::NonZero; use crate::path::Path; -use crate::sys::pipe::{AnonPipe, read2}; use crate::sys::process as imp; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::{fmt, fs, str}; @@ -300,9 +299,9 @@ impl fmt::Debug for Child { /// /// Used to pass pipe handles between this module and [`imp`]. pub(crate) struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, + pub stdin: Option, + pub stdout: Option, + pub stderr: Option, } /// A handle to a child process's standard input (stdin). @@ -317,7 +316,7 @@ pub(crate) struct StdioPipes { /// [dropped]: Drop #[stable(feature = "process", since = "1.0.0")] pub struct ChildStdin { - inner: AnonPipe, + inner: imp::ChildPipe, } // In addition to the `impl`s here, `ChildStdin` also has `impl`s for @@ -366,21 +365,21 @@ impl Write for &ChildStdin { } } -impl AsInner for ChildStdin { +impl AsInner for ChildStdin { #[inline] - fn as_inner(&self) -> &AnonPipe { + fn as_inner(&self) -> &imp::ChildPipe { &self.inner } } -impl IntoInner for ChildStdin { - fn into_inner(self) -> AnonPipe { +impl IntoInner for ChildStdin { + fn into_inner(self) -> imp::ChildPipe { self.inner } } -impl FromInner for ChildStdin { - fn from_inner(pipe: AnonPipe) -> ChildStdin { +impl FromInner for ChildStdin { + fn from_inner(pipe: imp::ChildPipe) -> ChildStdin { ChildStdin { inner: pipe } } } @@ -403,7 +402,7 @@ impl fmt::Debug for ChildStdin { /// [dropped]: Drop #[stable(feature = "process", since = "1.0.0")] pub struct ChildStdout { - inner: AnonPipe, + inner: imp::ChildPipe, } // In addition to the `impl`s here, `ChildStdout` also has `impl`s for @@ -436,21 +435,21 @@ impl Read for ChildStdout { } } -impl AsInner for ChildStdout { +impl AsInner for ChildStdout { #[inline] - fn as_inner(&self) -> &AnonPipe { + fn as_inner(&self) -> &imp::ChildPipe { &self.inner } } -impl IntoInner for ChildStdout { - fn into_inner(self) -> AnonPipe { +impl IntoInner for ChildStdout { + fn into_inner(self) -> imp::ChildPipe { self.inner } } -impl FromInner for ChildStdout { - fn from_inner(pipe: AnonPipe) -> ChildStdout { +impl FromInner for ChildStdout { + fn from_inner(pipe: imp::ChildPipe) -> ChildStdout { ChildStdout { inner: pipe } } } @@ -473,7 +472,7 @@ impl fmt::Debug for ChildStdout { /// [dropped]: Drop #[stable(feature = "process", since = "1.0.0")] pub struct ChildStderr { - inner: AnonPipe, + inner: imp::ChildPipe, } // In addition to the `impl`s here, `ChildStderr` also has `impl`s for @@ -506,21 +505,21 @@ impl Read for ChildStderr { } } -impl AsInner for ChildStderr { +impl AsInner for ChildStderr { #[inline] - fn as_inner(&self) -> &AnonPipe { + fn as_inner(&self) -> &imp::ChildPipe { &self.inner } } -impl IntoInner for ChildStderr { - fn into_inner(self) -> AnonPipe { +impl IntoInner for ChildStderr { + fn into_inner(self) -> imp::ChildPipe { self.inner } } -impl FromInner for ChildStderr { - fn from_inner(pipe: AnonPipe) -> ChildStderr { +impl FromInner for ChildStderr { + fn from_inner(pipe: imp::ChildPipe) -> ChildStderr { ChildStderr { inner: pipe } } } @@ -2380,7 +2379,7 @@ impl Child { res.unwrap(); } (Some(out), Some(err)) => { - let res = read2(out.inner, &mut stdout, err.inner, &mut stderr); + let res = imp::read_output(out.inner, &mut stdout, err.inner, &mut stderr); res.unwrap(); } } diff --git a/library/std/src/sys/anonymous_pipe/motor.rs b/library/std/src/sys/anonymous_pipe/motor.rs deleted file mode 100644 index dfe10f7fafe49..0000000000000 --- a/library/std/src/sys/anonymous_pipe/motor.rs +++ /dev/null @@ -1,11 +0,0 @@ -use crate::io; -use crate::sys::fd::FileDesc; -use crate::sys::pipe::anon_pipe; -use crate::sys_common::IntoInner; - -pub type AnonPipe = FileDesc; - -#[inline] -pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { - anon_pipe().map(|(rx, wx)| (rx.into_inner(), wx.into_inner())) -} diff --git a/library/std/src/sys/anonymous_pipe/unix.rs b/library/std/src/sys/anonymous_pipe/unix.rs deleted file mode 100644 index dfe10f7fafe49..0000000000000 --- a/library/std/src/sys/anonymous_pipe/unix.rs +++ /dev/null @@ -1,11 +0,0 @@ -use crate::io; -use crate::sys::fd::FileDesc; -use crate::sys::pipe::anon_pipe; -use crate::sys_common::IntoInner; - -pub type AnonPipe = FileDesc; - -#[inline] -pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { - anon_pipe().map(|(rx, wx)| (rx.into_inner(), wx.into_inner())) -} diff --git a/library/std/src/sys/anonymous_pipe/unsupported.rs b/library/std/src/sys/anonymous_pipe/unsupported.rs deleted file mode 100644 index a0805ba9540e0..0000000000000 --- a/library/std/src/sys/anonymous_pipe/unsupported.rs +++ /dev/null @@ -1,7 +0,0 @@ -use crate::io; -pub use crate::sys::pipe::AnonPipe; - -#[inline] -pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { - Err(io::Error::UNSUPPORTED_PLATFORM) -} diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 507d093d2b2f6..74206405bfe7b 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -2077,12 +2077,25 @@ pub fn symlink(original: &CStr, link: &CStr) -> io::Result<()> { pub fn link(original: &CStr, link: &CStr) -> io::Result<()> { cfg_select! { - any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_env = "nto70") => { - // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves - // it implementation-defined whether `link` follows symlinks, so rely on the - // `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior. - // Android has `linkat` on newer versions, but we happen to know `link` - // always has the correct behavior, so it's here as well. + any( + // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. + // POSIX leaves it implementation-defined whether `link` follows + // symlinks, so rely on the `symlink_hard_link` test in + // library/std/src/fs/tests.rs to check the behavior. + target_os = "vxworks", + target_os = "redox", + target_os = "espidf", + // Android has `linkat` on newer versions, but we happen to know + // `link` always has the correct behavior, so it's here as well. + target_os = "android", + // wasi-sdk-29-and-prior have a buggy `linkat` so use `link` instead + // until wasi-sdk is updated (see WebAssembly/wasi-libc#690) + target_os = "wasi", + // Other misc platforms + target_os = "horizon", + target_os = "vita", + target_env = "nto70", + ) => { cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?; } _ => { diff --git a/library/std/src/sys/io/kernel_copy/linux/tests.rs b/library/std/src/sys/io/kernel_copy/linux/tests.rs index 15dee768d928b..9b2d9cbef9902 100644 --- a/library/std/src/sys/io/kernel_copy/linux/tests.rs +++ b/library/std/src/sys/io/kernel_copy/linux/tests.rs @@ -88,13 +88,8 @@ fn dont_splice_pipes_from_files() -> Result<()> { use crate::io::SeekFrom; use crate::os::unix::fs::FileExt; - use crate::process::{ChildStdin, ChildStdout}; - use crate::sys_common::FromInner; - let (read_end, write_end) = crate::sys::pipe::anon_pipe()?; - - let mut read_end = ChildStdout::from_inner(read_end); - let mut write_end = ChildStdin::from_inner(write_end); + let (mut read_end, mut write_end) = crate::io::pipe()?; let tmp_path = tmpdir(); let file = tmp_path.join("to_be_modified"); @@ -220,13 +215,8 @@ fn bench_file_to_uds_copy(b: &mut test::Bencher) { fn bench_socket_pipe_socket_copy(b: &mut test::Bencher) { use super::CopyResult; use crate::io::ErrorKind; - use crate::process::{ChildStdin, ChildStdout}; - use crate::sys_common::FromInner; - - let (read_end, write_end) = crate::sys::pipe::anon_pipe().unwrap(); - let mut read_end = ChildStdout::from_inner(read_end); - let write_end = ChildStdin::from_inner(write_end); + let (mut read_end, write_end) = crate::io::pipe().unwrap(); let acceptor = crate::net::TcpListener::bind("localhost:0").unwrap(); let mut remote_end = crate::net::TcpStream::connect(acceptor.local_addr().unwrap()).unwrap(); diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 2dbdc8a4e026e..3c44543bce321 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -13,7 +13,6 @@ mod pal; mod alloc; mod personality; -pub mod anonymous_pipe; pub mod args; pub mod backtrace; pub mod cmath; @@ -26,6 +25,7 @@ pub mod io; pub mod net; pub mod os_str; pub mod path; +pub mod pipe; pub mod platform_version; pub mod process; pub mod random; diff --git a/library/std/src/sys/pal/common/mod.rs b/library/std/src/sys/pal/common/mod.rs index 9af4dee401cf3..8f89df813b7fe 100644 --- a/library/std/src/sys/pal/common/mod.rs +++ b/library/std/src/sys/pal/common/mod.rs @@ -11,6 +11,7 @@ #![allow(dead_code)] pub mod small_c_string; +pub(crate) mod timespec; #[cfg(test)] mod tests; diff --git a/library/std/src/sys/pal/common/timespec.rs b/library/std/src/sys/pal/common/timespec.rs new file mode 100644 index 0000000000000..40d55c17b594a --- /dev/null +++ b/library/std/src/sys/pal/common/timespec.rs @@ -0,0 +1,179 @@ +use core::num::niche_types::Nanoseconds; + +use crate::io; +use crate::time::Duration; + +const NSEC_PER_SEC: u64 = 1_000_000_000; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub(crate) struct Timespec { + pub(crate) tv_sec: i64, + pub(crate) tv_nsec: Nanoseconds, +} + +impl Timespec { + const unsafe fn new_unchecked(tv_sec: i64, tv_nsec: i64) -> Timespec { + Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds::new_unchecked(tv_nsec as u32) } } + } + + pub const fn zero() -> Timespec { + unsafe { Self::new_unchecked(0, 0) } + } + + pub(crate) const fn new(tv_sec: i64, tv_nsec: i64) -> Result { + // On Apple OS, dates before epoch are represented differently than on other + // Unix platforms: e.g. 1/10th of a second before epoch is represented as `seconds=-1` + // and `nanoseconds=100_000_000` on other platforms, but is `seconds=0` and + // `nanoseconds=-900_000_000` on Apple OS. + // + // To compensate, we first detect this special case by checking if both + // seconds and nanoseconds are in range, and then correct the value for seconds + // and nanoseconds to match the common unix representation. + // + // Please note that Apple OS nonetheless accepts the standard unix format when + // setting file times, which makes this compensation round-trippable and generally + // transparent. + #[cfg(target_vendor = "apple")] + let (tv_sec, tv_nsec) = + if (tv_sec <= 0 && tv_sec > i64::MIN) && (tv_nsec < 0 && tv_nsec > -1_000_000_000) { + (tv_sec - 1, tv_nsec + 1_000_000_000) + } else { + (tv_sec, tv_nsec) + }; + if tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64 { + Ok(unsafe { Self::new_unchecked(tv_sec, tv_nsec) }) + } else { + Err(io::const_error!(io::ErrorKind::InvalidData, "invalid timestamp")) + } + } + + #[cfg(any(unix, target_os = "wasi"))] + pub fn now(clock: libc::clockid_t) -> Timespec { + use crate::mem::MaybeUninit; + use crate::sys::cvt; + + // Try to use 64-bit time in preparation for Y2038. + #[cfg(all( + target_os = "linux", + target_env = "gnu", + target_pointer_width = "32", + not(target_arch = "riscv32") + ))] + { + use crate::sys::time::__timespec64; + use crate::sys::weak::weak; + + // __clock_gettime64 was added to 32-bit arches in glibc 2.34, + // and it handles both vDSO calls and ENOSYS fallbacks itself. + weak!( + fn __clock_gettime64( + clockid: libc::clockid_t, + tp: *mut __timespec64, + ) -> libc::c_int; + ); + + if let Some(clock_gettime64) = __clock_gettime64.get() { + let mut t = MaybeUninit::uninit(); + cvt(unsafe { clock_gettime64(clock, t.as_mut_ptr()) }).unwrap(); + let t = unsafe { t.assume_init() }; + return Timespec::new(t.tv_sec as i64, t.tv_nsec as i64).unwrap(); + } + } + + let mut t = MaybeUninit::uninit(); + cvt(unsafe { libc::clock_gettime(clock, t.as_mut_ptr()) }).unwrap(); + let t = unsafe { t.assume_init() }; + Timespec::new(t.tv_sec as i64, t.tv_nsec as i64).unwrap() + } + + pub fn sub_timespec(&self, other: &Timespec) -> Result { + // When a >= b, the difference fits in u64. + fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 { + debug_assert!(a >= b); + a.wrapping_sub(b).cast_unsigned() + } + + if self >= other { + let (secs, nsec) = if self.tv_nsec.as_inner() >= other.tv_nsec.as_inner() { + ( + sub_ge_to_unsigned(self.tv_sec, other.tv_sec), + self.tv_nsec.as_inner() - other.tv_nsec.as_inner(), + ) + } else { + // Following sequence of assertions explain why `self.tv_sec - 1` does not underflow. + debug_assert!(self.tv_nsec < other.tv_nsec); + debug_assert!(self.tv_sec > other.tv_sec); + debug_assert!(self.tv_sec > i64::MIN); + ( + sub_ge_to_unsigned(self.tv_sec - 1, other.tv_sec), + self.tv_nsec.as_inner() + (NSEC_PER_SEC as u32) - other.tv_nsec.as_inner(), + ) + }; + + Ok(Duration::new(secs, nsec)) + } else { + match other.sub_timespec(self) { + Ok(d) => Err(d), + Err(d) => Ok(d), + } + } + } + + pub fn checked_add_duration(&self, other: &Duration) -> Option { + let mut secs = self.tv_sec.checked_add_unsigned(other.as_secs())?; + + // Nano calculations can't overflow because nanos are <1B which fit + // in a u32. + let mut nsec = other.subsec_nanos() + self.tv_nsec.as_inner(); + if nsec >= NSEC_PER_SEC as u32 { + nsec -= NSEC_PER_SEC as u32; + secs = secs.checked_add(1)?; + } + Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) }) + } + + pub fn checked_sub_duration(&self, other: &Duration) -> Option { + let mut secs = self.tv_sec.checked_sub_unsigned(other.as_secs())?; + + // Similar to above, nanos can't overflow. + let mut nsec = self.tv_nsec.as_inner() as i32 - other.subsec_nanos() as i32; + if nsec < 0 { + nsec += NSEC_PER_SEC as i32; + secs = secs.checked_sub(1)?; + } + Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) }) + } + + #[allow(dead_code)] + #[cfg(any(unix, target_os = "wasi"))] + pub fn to_timespec(&self) -> Option { + Some(libc::timespec { + tv_sec: self.tv_sec.try_into().ok()?, + tv_nsec: self.tv_nsec.as_inner().try_into().ok()?, + }) + } + + // On QNX Neutrino, the maximum timespec for e.g. pthread_cond_timedwait + // is 2^64 nanoseconds + #[cfg(target_os = "nto")] + pub(in crate::sys) fn to_timespec_capped(&self) -> Option { + // Check if timeout in nanoseconds would fit into an u64 + if (self.tv_nsec.as_inner() as u64) + .checked_add((self.tv_sec as u64).checked_mul(NSEC_PER_SEC)?) + .is_none() + { + return None; + } + self.to_timespec() + } + + #[cfg(all( + target_os = "linux", + target_env = "gnu", + target_pointer_width = "32", + not(target_arch = "riscv32") + ))] + pub fn to_timespec64(&self) -> crate::sys::time::__timespec64 { + crate::sys::time::__timespec64::new(self.tv_sec, self.tv_nsec.as_inner() as _) + } +} diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index 3ddf6e5acb02e..52bcd8da24209 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -23,8 +23,6 @@ use crate::sys::env; pub mod futex; pub mod os; -#[path = "../unsupported/pipe.rs"] -pub mod pipe; pub mod time; pub fn unsupported() -> crate::io::Result { diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index bd6fd5a3de428..22b0bc553bda3 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -1,122 +1,23 @@ #![allow(dead_code)] -use core::hash::{Hash, Hasher}; +use core::hash::Hash; use super::hermit_abi::{self, CLOCK_MONOTONIC, CLOCK_REALTIME, timespec}; -use crate::cmp::Ordering; use crate::ops::{Add, AddAssign, Sub, SubAssign}; +use crate::sys::common::timespec::Timespec; use crate::time::Duration; const NSEC_PER_SEC: i32 = 1_000_000_000; -#[derive(Copy, Clone, Debug)] -struct Timespec { - t: timespec, -} - -impl Timespec { - const fn zero() -> Timespec { - Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } } - } - - const fn new(tv_sec: i64, tv_nsec: i32) -> Timespec { - assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC); - // SAFETY: The assert above checks tv_nsec is within the valid range - Timespec { t: timespec { tv_sec, tv_nsec } } - } - - fn sub_timespec(&self, other: &Timespec) -> Result { - fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 { - debug_assert!(a >= b); - a.wrapping_sub(b).cast_unsigned() - } - - if self >= other { - // Logic here is identical to Unix version of `Timestamp::sub_timespec`, - // check comments there why operations do not overflow. - Ok(if self.t.tv_nsec >= other.t.tv_nsec { - Duration::new( - sub_ge_to_unsigned(self.t.tv_sec, other.t.tv_sec), - (self.t.tv_nsec - other.t.tv_nsec) as u32, - ) - } else { - Duration::new( - sub_ge_to_unsigned(self.t.tv_sec - 1, other.t.tv_sec), - (self.t.tv_nsec + NSEC_PER_SEC - other.t.tv_nsec) as u32, - ) - }) - } else { - match other.sub_timespec(self) { - Ok(d) => Err(d), - Err(d) => Ok(d), - } - } - } - - fn checked_add_duration(&self, other: &Duration) -> Option { - let mut secs = self.t.tv_sec.checked_add_unsigned(other.as_secs())?; - - // Nano calculations can't overflow because nanos are <1B which fit - // in a u32. - let mut nsec = other.subsec_nanos() + u32::try_from(self.t.tv_nsec).unwrap(); - if nsec >= NSEC_PER_SEC.try_into().unwrap() { - nsec -= u32::try_from(NSEC_PER_SEC).unwrap(); - secs = secs.checked_add(1)?; - } - Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } }) - } - - fn checked_sub_duration(&self, other: &Duration) -> Option { - let mut secs = self.t.tv_sec.checked_sub_unsigned(other.as_secs())?; - - // Similar to above, nanos can't overflow. - let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; - if nsec < 0 { - nsec += NSEC_PER_SEC as i32; - secs = secs.checked_sub(1)?; - } - Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } }) - } -} - -impl PartialEq for Timespec { - fn eq(&self, other: &Timespec) -> bool { - self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec - } -} - -impl Eq for Timespec {} - -impl PartialOrd for Timespec { - fn partial_cmp(&self, other: &Timespec) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Timespec { - fn cmp(&self, other: &Timespec) -> Ordering { - let me = (self.t.tv_sec, self.t.tv_nsec); - let other = (other.t.tv_sec, other.t.tv_nsec); - me.cmp(&other) - } -} - -impl Hash for Timespec { - fn hash(&self, state: &mut H) { - self.t.tv_sec.hash(state); - self.t.tv_nsec.hash(state); - } -} - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] pub struct Instant(Timespec); impl Instant { pub fn now() -> Instant { - let mut time: Timespec = Timespec::zero(); - let _ = unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, &raw mut time.t) }; + let mut time: timespec = timespec { tv_sec: 0, tv_nsec: 0 }; + let _ = unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, &raw mut time) }; - Instant(time) + Instant(Timespec::new(time.tv_sec, time.tv_nsec as i64).unwrap()) } #[stable(feature = "time2", since = "1.8.0")] @@ -210,14 +111,13 @@ pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero()); impl SystemTime { pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime { - SystemTime(Timespec::new(tv_sec, tv_nsec)) + SystemTime(Timespec::new(tv_sec, tv_nsec as i64).unwrap()) } pub fn now() -> SystemTime { - let mut time: Timespec = Timespec::zero(); - let _ = unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, &raw mut time.t) }; - - SystemTime(time) + let mut time: timespec = timespec { tv_sec: 0, tv_nsec: 0 }; + let _ = unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, &raw mut time) }; + SystemTime::new(time.tv_sec, time.tv_nsec) } pub fn sub_time(&self, other: &SystemTime) -> Result { diff --git a/library/std/src/sys/pal/motor/mod.rs b/library/std/src/sys/pal/motor/mod.rs index 32f95df6ad082..9bca264d78ea9 100644 --- a/library/std/src/sys/pal/motor/mod.rs +++ b/library/std/src/sys/pal/motor/mod.rs @@ -1,7 +1,6 @@ #![allow(unsafe_op_in_unsafe_fn)] pub mod os; -pub mod pipe; pub mod time; pub use moto_rt::futex; diff --git a/library/std/src/sys/pal/motor/pipe.rs b/library/std/src/sys/pal/motor/pipe.rs deleted file mode 100644 index d3be6ddf1573e..0000000000000 --- a/library/std/src/sys/pal/motor/pipe.rs +++ /dev/null @@ -1,121 +0,0 @@ -use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; -use crate::sys::fd::FileDesc; -use crate::sys::map_motor_error; -use crate::sys_common::{FromInner, IntoInner}; - -#[derive(Debug)] -pub struct AnonPipe(FileDesc); - -impl From for AnonPipe { - fn from(rt_fd: moto_rt::RtFd) -> AnonPipe { - unsafe { AnonPipe::from_raw_fd(rt_fd) } - } -} - -impl AnonPipe { - pub fn read(&self, buf: &mut [u8]) -> io::Result { - moto_rt::fs::read(self.as_raw_fd(), buf).map_err(map_motor_error) - } - - pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { - crate::io::default_read_buf(|buf| self.read(buf), cursor) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - crate::io::default_read_vectored(|b| self.read(b), bufs) - } - - pub fn is_read_vectored(&self) -> bool { - false - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - moto_rt::fs::write(self.as_raw_fd(), buf).map_err(map_motor_error) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - crate::io::default_write_vectored(|b| self.write(b), bufs) - } - - pub fn is_write_vectored(&self) -> bool { - false - } - - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - let mut temp_vec = Vec::new(); - let mut size = 0_usize; - loop { - temp_vec.resize(256, 0_u8); - match self.read(&mut temp_vec[..]) { - Ok(sz) => { - if sz == 0 { - return Ok(size); - } - size += sz; - temp_vec.truncate(sz); - buf.append(&mut temp_vec); - } - Err(err) => { - if size != 0 { - return Ok(size); - } else { - return Err(err); - } - } - } - } - } -} - -impl AsRawFd for AnonPipe { - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} - -impl FromRawFd for AnonPipe { - unsafe fn from_raw_fd(fd: RawFd) -> Self { - let desc = FileDesc::from_raw_fd(fd); - Self(desc) - } -} - -impl IntoRawFd for AnonPipe { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw_fd() - } -} - -impl AsFd for AnonPipe { - fn as_fd(&self) -> BorrowedFd<'_> { - self.0.as_fd() - } -} - -impl IntoInner for AnonPipe { - fn into_inner(self) -> OwnedFd { - self.0.into_inner() - } -} - -impl IntoInner for AnonPipe { - fn into_inner(self) -> FileDesc { - self.0 - } -} - -impl FromInner for AnonPipe { - fn from_inner(owned_fd: OwnedFd) -> Self { - Self(FileDesc::from_inner(owned_fd)) - } -} - -pub fn read2(_p1: AnonPipe, _v1: &mut Vec, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { - Err(io::Error::from_raw_os_error(moto_rt::E_NOT_IMPLEMENTED.into())) -} - -#[inline] -pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { - Err(io::Error::UNSUPPORTED_PLATFORM) -} diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 9a33873af581f..5d57be59aadf7 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -11,8 +11,6 @@ use crate::sync::atomic::{Atomic, AtomicBool, Ordering}; pub mod abi; mod libunwind_integration; pub mod os; -#[path = "../unsupported/pipe.rs"] -pub mod pipe; pub mod thread_parking; pub mod time; pub mod waitqueue; diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index 9ca6dc581183d..33df9116f5c2d 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -18,8 +18,6 @@ pub mod itron { // `crate::sys::error` pub(crate) mod error; pub mod os; -#[path = "../unsupported/pipe.rs"] -pub mod pipe; pub use self::itron::thread_parking; pub mod time; diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index dd0155265da63..fe2dd9c6c493e 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -7,8 +7,6 @@ #![allow(dead_code)] pub mod os; -#[path = "../unsupported/pipe.rs"] -pub mod pipe; #[allow(non_upper_case_globals)] #[path = "../unix/time.rs"] pub mod time; diff --git a/library/std/src/sys/pal/trusty/mod.rs b/library/std/src/sys/pal/trusty/mod.rs index cf0c098f8a2f3..76a3a75b10c1a 100644 --- a/library/std/src/sys/pal/trusty/mod.rs +++ b/library/std/src/sys/pal/trusty/mod.rs @@ -5,8 +5,6 @@ mod common; #[path = "../unsupported/os.rs"] pub mod os; -#[path = "../unsupported/pipe.rs"] -pub mod pipe; #[path = "../unsupported/time.rs"] pub mod time; diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index ebd311db1e12c..e8236437b9c97 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -15,8 +15,6 @@ pub mod helpers; pub mod os; -#[path = "../unsupported/pipe.rs"] -pub mod pipe; pub mod time; #[cfg(test)] diff --git a/library/std/src/sys/pal/unix/futex.rs b/library/std/src/sys/pal/unix/futex.rs index 265067d84d502..5c238d9a2fb81 100644 --- a/library/std/src/sys/pal/unix/futex.rs +++ b/library/std/src/sys/pal/unix/futex.rs @@ -28,9 +28,9 @@ pub type SmallPrimitive = u32; /// Returns false on timeout, and true in all other cases. #[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))] pub fn futex_wait(futex: &Atomic, expected: u32, timeout: Option) -> bool { - use super::time::Timespec; use crate::ptr::null; use crate::sync::atomic::Ordering::Relaxed; + use crate::sys::common::timespec::Timespec; // Calculate the timeout as an absolute timespec. // diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 81533d593131b..a6c5decf2d341 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -8,7 +8,6 @@ pub mod futex; #[cfg(target_os = "linux")] pub mod linux; pub mod os; -pub mod pipe; pub mod stack_overflow; pub mod sync; pub mod thread_parking; diff --git a/library/std/src/sys/pal/unix/pipe.rs b/library/std/src/sys/pal/unix/pipe.rs deleted file mode 100644 index 4798acf9dad6b..0000000000000 --- a/library/std/src/sys/pal/unix/pipe.rs +++ /dev/null @@ -1,184 +0,0 @@ -use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::mem; -use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; -use crate::sys::fd::FileDesc; -use crate::sys::{cvt, cvt_r}; -use crate::sys_common::{FromInner, IntoInner}; - -//////////////////////////////////////////////////////////////////////////////// -// Anonymous pipes -//////////////////////////////////////////////////////////////////////////////// - -#[derive(Debug)] -pub struct AnonPipe(FileDesc); - -pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { - let mut fds = [0; 2]; - - // The only known way right now to create atomically set the CLOEXEC flag is - // to use the `pipe2` syscall. This was added to Linux in 2.6.27, glibc 2.9 - // and musl 0.9.3, and some other targets also have it. - cfg_select! { - any( - target_os = "android", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "hurd", - target_os = "illumos", - target_os = "linux", - target_os = "netbsd", - target_os = "openbsd", - target_os = "cygwin", - target_os = "redox" - ) => { - unsafe { - cvt(libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC))?; - Ok((AnonPipe(FileDesc::from_raw_fd(fds[0])), AnonPipe(FileDesc::from_raw_fd(fds[1])))) - } - } - _ => { - unsafe { - cvt(libc::pipe(fds.as_mut_ptr()))?; - - let fd0 = FileDesc::from_raw_fd(fds[0]); - let fd1 = FileDesc::from_raw_fd(fds[1]); - fd0.set_cloexec()?; - fd1.set_cloexec()?; - Ok((AnonPipe(fd0), AnonPipe(fd1))) - } - } - } -} - -impl AnonPipe { - #[allow(dead_code)] - // FIXME: This function seems legitimately unused. - pub fn try_clone(&self) -> io::Result { - self.0.duplicate().map(Self) - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - - pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { - self.0.read_buf(buf) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0.read_vectored(bufs) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - - pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - self.0.read_to_end(buf) - } - - pub fn write(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { - self.0.write_vectored(bufs) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - #[allow(dead_code)] - // FIXME: This function seems legitimately unused. - pub fn as_file_desc(&self) -> &FileDesc { - &self.0 - } -} - -impl IntoInner for AnonPipe { - fn into_inner(self) -> FileDesc { - self.0 - } -} - -pub fn read2(p1: AnonPipe, v1: &mut Vec, p2: AnonPipe, v2: &mut Vec) -> io::Result<()> { - // Set both pipes into nonblocking mode as we're gonna be reading from both - // in the `select` loop below, and we wouldn't want one to block the other! - let p1 = p1.into_inner(); - let p2 = p2.into_inner(); - p1.set_nonblocking(true)?; - p2.set_nonblocking(true)?; - - let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; - fds[0].fd = p1.as_raw_fd(); - fds[0].events = libc::POLLIN; - fds[1].fd = p2.as_raw_fd(); - fds[1].events = libc::POLLIN; - loop { - // wait for either pipe to become readable using `poll` - cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?; - - if fds[0].revents != 0 && read(&p1, v1)? { - p2.set_nonblocking(false)?; - return p2.read_to_end(v2).map(drop); - } - if fds[1].revents != 0 && read(&p2, v2)? { - p1.set_nonblocking(false)?; - return p1.read_to_end(v1).map(drop); - } - } - - // Read as much as we can from each pipe, ignoring EWOULDBLOCK or - // EAGAIN. If we hit EOF, then this will happen because the underlying - // reader will return Ok(0), in which case we'll see `Ok` ourselves. In - // this case we flip the other fd back into blocking mode and read - // whatever's leftover on that file descriptor. - fn read(fd: &FileDesc, dst: &mut Vec) -> Result { - match fd.read_to_end(dst) { - Ok(_) => Ok(true), - Err(e) => { - if e.raw_os_error() == Some(libc::EWOULDBLOCK) - || e.raw_os_error() == Some(libc::EAGAIN) - { - Ok(false) - } else { - Err(e) - } - } - } - } -} - -impl AsRawFd for AnonPipe { - #[inline] - fn as_raw_fd(&self) -> RawFd { - self.0.as_raw_fd() - } -} - -impl AsFd for AnonPipe { - fn as_fd(&self) -> BorrowedFd<'_> { - self.0.as_fd() - } -} - -impl IntoRawFd for AnonPipe { - fn into_raw_fd(self) -> RawFd { - self.0.into_raw_fd() - } -} - -impl FromRawFd for AnonPipe { - unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { - Self(FromRawFd::from_raw_fd(raw_fd)) - } -} - -impl FromInner for AnonPipe { - fn from_inner(fd: FileDesc) -> Self { - Self(fd) - } -} diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index 24f13853b96b3..97a44b920c04d 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -1,10 +1,8 @@ -use core::num::niche_types::Nanoseconds; - +use crate::sys::common::timespec::Timespec; use crate::sys_common::AsInner; use crate::time::Duration; use crate::{fmt, io}; -const NSEC_PER_SEC: u64 = 1_000_000_000; pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() }; #[allow(dead_code)] // Used for pthread condvar timeouts pub const TIMESPEC_MAX: libc::timespec = @@ -23,12 +21,6 @@ pub struct SystemTime { pub(crate) t: Timespec, } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) struct Timespec { - tv_sec: i64, - tv_nsec: Nanoseconds, -} - impl SystemTime { #[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))] pub fn new(tv_sec: i64, tv_nsec: i64) -> Result { @@ -61,170 +53,6 @@ impl fmt::Debug for SystemTime { } } -impl Timespec { - const unsafe fn new_unchecked(tv_sec: i64, tv_nsec: i64) -> Timespec { - Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds::new_unchecked(tv_nsec as u32) } } - } - - pub const fn zero() -> Timespec { - unsafe { Self::new_unchecked(0, 0) } - } - - const fn new(tv_sec: i64, tv_nsec: i64) -> Result { - // On Apple OS, dates before epoch are represented differently than on other - // Unix platforms: e.g. 1/10th of a second before epoch is represented as `seconds=-1` - // and `nanoseconds=100_000_000` on other platforms, but is `seconds=0` and - // `nanoseconds=-900_000_000` on Apple OS. - // - // To compensate, we first detect this special case by checking if both - // seconds and nanoseconds are in range, and then correct the value for seconds - // and nanoseconds to match the common unix representation. - // - // Please note that Apple OS nonetheless accepts the standard unix format when - // setting file times, which makes this compensation round-trippable and generally - // transparent. - #[cfg(target_vendor = "apple")] - let (tv_sec, tv_nsec) = - if (tv_sec <= 0 && tv_sec > i64::MIN) && (tv_nsec < 0 && tv_nsec > -1_000_000_000) { - (tv_sec - 1, tv_nsec + 1_000_000_000) - } else { - (tv_sec, tv_nsec) - }; - if tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64 { - Ok(unsafe { Self::new_unchecked(tv_sec, tv_nsec) }) - } else { - Err(io::const_error!(io::ErrorKind::InvalidData, "invalid timestamp")) - } - } - - pub fn now(clock: libc::clockid_t) -> Timespec { - use crate::mem::MaybeUninit; - use crate::sys::cvt; - - // Try to use 64-bit time in preparation for Y2038. - #[cfg(all( - target_os = "linux", - target_env = "gnu", - target_pointer_width = "32", - not(target_arch = "riscv32") - ))] - { - use crate::sys::weak::weak; - - // __clock_gettime64 was added to 32-bit arches in glibc 2.34, - // and it handles both vDSO calls and ENOSYS fallbacks itself. - weak!( - fn __clock_gettime64( - clockid: libc::clockid_t, - tp: *mut __timespec64, - ) -> libc::c_int; - ); - - if let Some(clock_gettime64) = __clock_gettime64.get() { - let mut t = MaybeUninit::uninit(); - cvt(unsafe { clock_gettime64(clock, t.as_mut_ptr()) }).unwrap(); - let t = unsafe { t.assume_init() }; - return Timespec::new(t.tv_sec as i64, t.tv_nsec as i64).unwrap(); - } - } - - let mut t = MaybeUninit::uninit(); - cvt(unsafe { libc::clock_gettime(clock, t.as_mut_ptr()) }).unwrap(); - let t = unsafe { t.assume_init() }; - Timespec::new(t.tv_sec as i64, t.tv_nsec as i64).unwrap() - } - - pub fn sub_timespec(&self, other: &Timespec) -> Result { - // When a >= b, the difference fits in u64. - fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 { - debug_assert!(a >= b); - a.wrapping_sub(b).cast_unsigned() - } - - if self >= other { - let (secs, nsec) = if self.tv_nsec.as_inner() >= other.tv_nsec.as_inner() { - ( - sub_ge_to_unsigned(self.tv_sec, other.tv_sec), - self.tv_nsec.as_inner() - other.tv_nsec.as_inner(), - ) - } else { - // Following sequence of assertions explain why `self.tv_sec - 1` does not underflow. - debug_assert!(self.tv_nsec < other.tv_nsec); - debug_assert!(self.tv_sec > other.tv_sec); - debug_assert!(self.tv_sec > i64::MIN); - ( - sub_ge_to_unsigned(self.tv_sec - 1, other.tv_sec), - self.tv_nsec.as_inner() + (NSEC_PER_SEC as u32) - other.tv_nsec.as_inner(), - ) - }; - - Ok(Duration::new(secs, nsec)) - } else { - match other.sub_timespec(self) { - Ok(d) => Err(d), - Err(d) => Ok(d), - } - } - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option { - let mut secs = self.tv_sec.checked_add_unsigned(other.as_secs())?; - - // Nano calculations can't overflow because nanos are <1B which fit - // in a u32. - let mut nsec = other.subsec_nanos() + self.tv_nsec.as_inner(); - if nsec >= NSEC_PER_SEC as u32 { - nsec -= NSEC_PER_SEC as u32; - secs = secs.checked_add(1)?; - } - Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) }) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option { - let mut secs = self.tv_sec.checked_sub_unsigned(other.as_secs())?; - - // Similar to above, nanos can't overflow. - let mut nsec = self.tv_nsec.as_inner() as i32 - other.subsec_nanos() as i32; - if nsec < 0 { - nsec += NSEC_PER_SEC as i32; - secs = secs.checked_sub(1)?; - } - Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) }) - } - - #[allow(dead_code)] - pub fn to_timespec(&self) -> Option { - Some(libc::timespec { - tv_sec: self.tv_sec.try_into().ok()?, - tv_nsec: self.tv_nsec.as_inner().try_into().ok()?, - }) - } - - // On QNX Neutrino, the maximum timespec for e.g. pthread_cond_timedwait - // is 2^64 nanoseconds - #[cfg(target_os = "nto")] - pub(in crate::sys) fn to_timespec_capped(&self) -> Option { - // Check if timeout in nanoseconds would fit into an u64 - if (self.tv_nsec.as_inner() as u64) - .checked_add((self.tv_sec as u64).checked_mul(NSEC_PER_SEC)?) - .is_none() - { - return None; - } - self.to_timespec() - } - - #[cfg(all( - target_os = "linux", - target_env = "gnu", - target_pointer_width = "32", - not(target_arch = "riscv32") - ))] - pub fn to_timespec64(&self) -> __timespec64 { - __timespec64::new(self.tv_sec, self.tv_nsec.as_inner() as _) - } -} - #[cfg(all( target_os = "linux", target_env = "gnu", diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs index e64bbc7c6169d..c33d2e5fb02a1 100644 --- a/library/std/src/sys/pal/unsupported/mod.rs +++ b/library/std/src/sys/pal/unsupported/mod.rs @@ -1,7 +1,6 @@ #![deny(unsafe_op_in_unsafe_fn)] pub mod os; -pub mod pipe; pub mod time; mod common; diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs index 42629a91e1afe..5d36687df0977 100644 --- a/library/std/src/sys/pal/wasi/mod.rs +++ b/library/std/src/sys/pal/wasi/mod.rs @@ -9,8 +9,6 @@ pub mod futex; pub mod os; -#[path = "../unsupported/pipe.rs"] -pub mod pipe; pub mod stack_overflow; #[path = "../unix/time.rs"] pub mod time; diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs index a20cd0e9ac776..80429a9aae18d 100644 --- a/library/std/src/sys/pal/wasm/mod.rs +++ b/library/std/src/sys/pal/wasm/mod.rs @@ -18,8 +18,6 @@ #[path = "../unsupported/os.rs"] pub mod os; -#[path = "../unsupported/pipe.rs"] -pub mod pipe; #[path = "../unsupported/time.rs"] pub mod time; diff --git a/library/std/src/sys/pal/windows/handle.rs b/library/std/src/sys/pal/windows/handle.rs index 712f41ba80308..fc17e0b5ebd3d 100644 --- a/library/std/src/sys/pal/windows/handle.rs +++ b/library/std/src/sys/pal/windows/handle.rs @@ -1,8 +1,5 @@ #![unstable(issue = "none", feature = "windows_handle")] -#[cfg(test)] -mod tests; - use core::ffi::c_void; use core::{cmp, mem, ptr}; diff --git a/library/std/src/sys/pal/windows/handle/tests.rs b/library/std/src/sys/pal/windows/handle/tests.rs deleted file mode 100644 index 0c976ed84e6ba..0000000000000 --- a/library/std/src/sys/pal/windows/handle/tests.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::sys::pipe::{Pipes, anon_pipe}; -use crate::{thread, time}; - -/// Test the synchronous fallback for overlapped I/O. -#[test] -fn overlapped_handle_fallback() { - // Create some pipes. `ours` will be asynchronous. - let Pipes { ours, theirs } = anon_pipe(true, false).unwrap(); - - let async_readable = ours.into_handle(); - let sync_writeable = theirs.into_handle(); - - thread::scope(|_| { - thread::sleep(time::Duration::from_millis(100)); - sync_writeable.write(b"hello world!").unwrap(); - }); - - // The pipe buffer starts empty so reading won't complete synchronously unless - // our fallback path works. - let mut buffer = [0u8; 1024]; - async_readable.read(&mut buffer).unwrap(); -} diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index a5f060080130f..32bd6ea3a4f6c 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -19,7 +19,6 @@ pub mod c; pub mod futex; pub mod handle; pub mod os; -pub mod pipe; pub mod time; cfg_select! { // We don't care about printing nice error messages for panic=immediate-abort diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs index e673157e0eb55..077cff1ee0f21 100644 --- a/library/std/src/sys/pal/xous/mod.rs +++ b/library/std/src/sys/pal/xous/mod.rs @@ -3,8 +3,6 @@ use crate::os::xous::ffi::exit; pub mod os; -#[path = "../unsupported/pipe.rs"] -pub mod pipe; pub mod time; #[path = "../unsupported/common.rs"] diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs index 9069c8d12fa1d..6dece1055a089 100644 --- a/library/std/src/sys/pal/zkvm/mod.rs +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -12,8 +12,6 @@ pub const WORD_SIZE: usize = size_of::(); pub mod abi; pub mod os; -#[path = "../unsupported/pipe.rs"] -pub mod pipe; #[path = "../unsupported/time.rs"] pub mod time; diff --git a/library/std/src/sys/anonymous_pipe/mod.rs b/library/std/src/sys/pipe/mod.rs similarity index 57% rename from library/std/src/sys/anonymous_pipe/mod.rs rename to library/std/src/sys/pipe/mod.rs index 64b2c014b54fe..85228963b4adf 100644 --- a/library/std/src/sys/anonymous_pipe/mod.rs +++ b/library/std/src/sys/pipe/mod.rs @@ -3,18 +3,18 @@ cfg_select! { unix => { mod unix; - pub use unix::{AnonPipe, pipe}; + pub use unix::{Pipe, pipe}; } windows => { mod windows; - pub use windows::{AnonPipe, pipe}; + pub use windows::{Pipe, pipe}; } target_os = "motor" => { mod motor; - pub use motor::{AnonPipe, pipe}; + pub use motor::{Pipe, pipe}; } _ => { mod unsupported; - pub use unsupported::{AnonPipe, pipe}; + pub use unsupported::{Pipe, pipe}; } } diff --git a/library/std/src/sys/pipe/motor.rs b/library/std/src/sys/pipe/motor.rs new file mode 100644 index 0000000000000..50787c5801339 --- /dev/null +++ b/library/std/src/sys/pipe/motor.rs @@ -0,0 +1,9 @@ +use crate::io; +use crate::sys::fd::FileDesc; + +pub type Pipe = FileDesc; + +#[inline] +pub fn pipe() -> io::Result<(Pipe, Pipe)> { + Err(io::Error::UNSUPPORTED_PLATFORM) +} diff --git a/library/std/src/sys/pipe/unix.rs b/library/std/src/sys/pipe/unix.rs new file mode 100644 index 0000000000000..bb97e806a0400 --- /dev/null +++ b/library/std/src/sys/pipe/unix.rs @@ -0,0 +1,44 @@ +use crate::io; +use crate::os::fd::FromRawFd; +use crate::sys::fd::FileDesc; +use crate::sys::pal::cvt; + +pub type Pipe = FileDesc; + +pub fn pipe() -> io::Result<(Pipe, Pipe)> { + let mut fds = [0; 2]; + + // The only known way right now to create atomically set the CLOEXEC flag is + // to use the `pipe2` syscall. This was added to Linux in 2.6.27, glibc 2.9 + // and musl 0.9.3, and some other targets also have it. + cfg_select! { + any( + target_os = "android", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "hurd", + target_os = "illumos", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd", + target_os = "cygwin", + target_os = "redox" + ) => { + unsafe { + cvt(libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC))?; + Ok((Pipe::from_raw_fd(fds[0]), Pipe::from_raw_fd(fds[1]))) + } + } + _ => { + unsafe { + cvt(libc::pipe(fds.as_mut_ptr()))?; + + let fd0 = Pipe::from_raw_fd(fds[0]); + let fd1 = Pipe::from_raw_fd(fds[1]); + fd0.set_cloexec()?; + fd1.set_cloexec()?; + Ok((fd0, fd1)) + } + } + } +} diff --git a/library/std/src/sys/pal/unsupported/pipe.rs b/library/std/src/sys/pipe/unsupported.rs similarity index 72% rename from library/std/src/sys/pal/unsupported/pipe.rs rename to library/std/src/sys/pipe/unsupported.rs index 988e551de5223..115e913e0f33a 100644 --- a/library/std/src/sys/pal/unsupported/pipe.rs +++ b/library/std/src/sys/pipe/unsupported.rs @@ -1,16 +1,14 @@ use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::sys_common::{FromInner, IntoInner}; -pub struct AnonPipe(!); +pub struct Pipe(!); -impl fmt::Debug for AnonPipe { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 - } +#[inline] +pub fn pipe() -> io::Result<(Pipe, Pipe)> { + Err(io::Error::UNSUPPORTED_PLATFORM) } -impl AnonPipe { +impl Pipe { pub fn try_clone(&self) -> io::Result { self.0 } @@ -52,56 +50,52 @@ impl AnonPipe { } } -pub fn read2(p1: AnonPipe, _v1: &mut Vec, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { - match p1.0 {} -} - -impl FromInner for AnonPipe { - fn from_inner(inner: !) -> Self { - inner - } -} - -impl IntoInner for AnonPipe { - fn into_inner(self) -> ! { +impl fmt::Debug for Pipe { + fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { self.0 } } #[cfg(any(unix, target_os = "hermit", target_os = "wasi"))] mod unix_traits { - use super::AnonPipe; + use super::Pipe; use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; - use crate::sys_common::FromInner; + use crate::sys_common::{FromInner, IntoInner}; - impl AsRawFd for AnonPipe { + impl AsRawFd for Pipe { #[inline] fn as_raw_fd(&self) -> RawFd { self.0 } } - impl AsFd for AnonPipe { + impl AsFd for Pipe { fn as_fd(&self) -> BorrowedFd<'_> { self.0 } } - impl IntoRawFd for AnonPipe { + impl IntoRawFd for Pipe { fn into_raw_fd(self) -> RawFd { self.0 } } - impl FromRawFd for AnonPipe { + impl FromRawFd for Pipe { unsafe fn from_raw_fd(_: RawFd) -> Self { panic!("creating pipe on this platform is unsupported!") } } - impl FromInner for AnonPipe { + impl FromInner for Pipe { fn from_inner(_: OwnedFd) -> Self { panic!("creating pipe on this platform is unsupported!") } } + + impl IntoInner for Pipe { + fn into_inner(self) -> OwnedFd { + self.0 + } + } } diff --git a/library/std/src/sys/anonymous_pipe/windows.rs b/library/std/src/sys/pipe/windows.rs similarity index 85% rename from library/std/src/sys/anonymous_pipe/windows.rs rename to library/std/src/sys/pipe/windows.rs index bdda7ffc5d251..5bd90b43d7427 100644 --- a/library/std/src/sys/anonymous_pipe/windows.rs +++ b/library/std/src/sys/pipe/windows.rs @@ -3,9 +3,9 @@ use crate::sys::c; use crate::sys::handle::Handle; use crate::{io, ptr}; -pub type AnonPipe = Handle; +pub type Pipe = Handle; -pub fn pipe() -> io::Result<(AnonPipe, AnonPipe)> { +pub fn pipe() -> io::Result<(Pipe, Pipe)> { let mut read_pipe = c::INVALID_HANDLE_VALUE; let mut write_pipe = c::INVALID_HANDLE_VALUE; diff --git a/library/std/src/sys/process/mod.rs b/library/std/src/sys/process/mod.rs index 92e459298fc4c..121d3bc9d5c3c 100644 --- a/library/std/src/sys/process/mod.rs +++ b/library/std/src/sys/process/mod.rs @@ -28,7 +28,8 @@ mod env; pub use env::CommandEnvs; pub use imp::{ - Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio, + ChildPipe, Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio, + read_output, }; #[cfg(any( @@ -45,8 +46,6 @@ pub use imp::{ target_os = "motor" ))] pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec, Vec)> { - use crate::sys::pipe::read2; - let (mut process, mut pipes) = cmd.spawn(Stdio::MakePipe, false)?; drop(pipes.stdin.take()); @@ -62,7 +61,7 @@ pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec, Vec< res.unwrap(); } (Some(out), Some(err)) => { - let res = read2(out, &mut stdout, err, &mut stderr); + let res = read_output(out, &mut stdout, err, &mut stderr); res.unwrap(); } } diff --git a/library/std/src/sys/process/motor.rs b/library/std/src/sys/process/motor.rs index 949a9d4942901..7a23a5d902c0a 100644 --- a/library/std/src/sys/process/motor.rs +++ b/library/std/src/sys/process/motor.rs @@ -9,7 +9,6 @@ use crate::path::Path; use crate::process::StdioPipes; use crate::sys::fs::File; use crate::sys::map_motor_error; -use crate::sys::pipe::AnonPipe; use crate::sys_common::{AsInner, FromInner}; use crate::{fmt, io}; @@ -150,20 +149,26 @@ impl Command { Ok(( Process { handle }, StdioPipes { - stdin: if stdin >= 0 { Some(stdin.into()) } else { None }, - stdout: if stdout >= 0 { Some(stdout.into()) } else { None }, - stderr: if stderr >= 0 { Some(stderr.into()) } else { None }, + stdin: if stdin >= 0 { + Some(unsafe { ChildPipe::from_raw_fd(stdin) }) + } else { + None + }, + stdout: if stdout >= 0 { + Some(unsafe { ChildPipe::from_raw_fd(stdout) }) + } else { + None + }, + stderr: if stderr >= 0 { + Some(unsafe { ChildPipe::from_raw_fd(stderr) }) + } else { + None + }, }, )) } } -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - unsafe { Stdio::Fd(crate::sys::fd::FileDesc::from_raw_fd(pipe.into_raw_fd())) } - } -} - impl From for Stdio { fn from(fd: crate::sys::fd::FileDesc) -> Stdio { Stdio::Fd(fd) @@ -315,3 +320,14 @@ impl<'a> fmt::Debug for CommandArgs<'a> { f.debug_list().entries(self.iter.clone()).finish() } } + +pub type ChildPipe = crate::sys::pipe::Pipe; + +pub fn read_output( + _out: ChildPipe, + _stdout: &mut Vec, + _err: ChildPipe, + _stderr: &mut Vec, +) -> io::Result<()> { + Err(io::Error::from_raw_os_error(moto_rt::E_NOT_IMPLEMENTED.into())) +} diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs index 8d44292611bcb..0e10bc02a0b90 100644 --- a/library/std/src/sys/process/uefi.rs +++ b/library/std/src/sys/process/uefi.rs @@ -10,7 +10,6 @@ use crate::process::StdioPipes; use crate::sys::fs::File; use crate::sys::pal::helpers; use crate::sys::pal::os::error_string; -use crate::sys::pipe::AnonPipe; use crate::sys::unsupported; use crate::{fmt, io}; @@ -204,8 +203,8 @@ pub fn output(command: &mut Command) -> io::Result<(ExitStatus, Vec, Vec Ok((ExitStatus(stat), stdout, stderr)) } -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { +impl From for Stdio { + fn from(pipe: ChildPipe) -> Stdio { pipe.diverge() } } @@ -356,6 +355,17 @@ impl<'a> fmt::Debug for CommandArgs<'a> { } } +pub type ChildPipe = crate::sys::pipe::Pipe; + +pub fn read_output( + out: ChildPipe, + _stdout: &mut Vec, + _err: ChildPipe, + _stderr: &mut Vec, +) -> io::Result<()> { + match out.diverge() {} +} + #[allow(dead_code)] mod uefi_command_internal { use r_efi::protocols::{loaded_image, simple_text_input, simple_text_output}; diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs index 44d54aaf51512..d4344d1191a43 100644 --- a/library/std/src/sys/process/unix/common.rs +++ b/library/std/src/sys/process/unix/common.rs @@ -10,14 +10,15 @@ use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::os::unix::prelude::*; use crate::path::Path; use crate::process::StdioPipes; +use crate::sys::cvt_r; use crate::sys::fd::FileDesc; use crate::sys::fs::File; #[cfg(not(target_os = "fuchsia"))] use crate::sys::fs::OpenOptions; -use crate::sys::pipe::{self, AnonPipe}; +use crate::sys::pipe::pipe; use crate::sys::process::env::{CommandEnv, CommandEnvs}; use crate::sys_common::{FromInner, IntoInner}; -use crate::{fmt, io}; +use crate::{fmt, io, mem}; mod cstring_array; @@ -393,7 +394,7 @@ fn construct_envp(env: BTreeMap, saw_nul: &mut bool) -> CStr } impl Stdio { - pub fn to_child_stdio(&self, readable: bool) -> io::Result<(ChildStdio, Option)> { + pub fn to_child_stdio(&self, readable: bool) -> io::Result<(ChildStdio, Option)> { match *self { Stdio::Inherit => Ok((ChildStdio::Inherit, None)), @@ -418,9 +419,9 @@ impl Stdio { } Stdio::MakePipe => { - let (reader, writer) = pipe::anon_pipe()?; + let (reader, writer) = pipe()?; let (ours, theirs) = if readable { (writer, reader) } else { (reader, writer) }; - Ok((ChildStdio::Owned(theirs.into_inner()), Some(ours))) + Ok((ChildStdio::Owned(theirs), Some(ours))) } #[cfg(not(target_os = "fuchsia"))] @@ -438,12 +439,6 @@ impl Stdio { } } -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - Stdio::Fd(pipe.into_inner()) - } -} - impl From for Stdio { fn from(fd: FileDesc) -> Stdio { Stdio::Fd(fd) @@ -632,3 +627,56 @@ impl<'a> fmt::Debug for CommandArgs<'a> { f.debug_list().entries(self.iter.clone()).finish() } } + +pub type ChildPipe = crate::sys::pipe::Pipe; + +pub fn read_output( + out: ChildPipe, + stdout: &mut Vec, + err: ChildPipe, + stderr: &mut Vec, +) -> io::Result<()> { + // Set both pipes into nonblocking mode as we're gonna be reading from both + // in the `select` loop below, and we wouldn't want one to block the other! + out.set_nonblocking(true)?; + err.set_nonblocking(true)?; + + let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; + fds[0].fd = out.as_raw_fd(); + fds[0].events = libc::POLLIN; + fds[1].fd = err.as_raw_fd(); + fds[1].events = libc::POLLIN; + loop { + // wait for either pipe to become readable using `poll` + cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?; + + if fds[0].revents != 0 && read(&out, stdout)? { + err.set_nonblocking(false)?; + return err.read_to_end(stderr).map(drop); + } + if fds[1].revents != 0 && read(&err, stderr)? { + out.set_nonblocking(false)?; + return out.read_to_end(stdout).map(drop); + } + } + + // Read as much as we can from each pipe, ignoring EWOULDBLOCK or + // EAGAIN. If we hit EOF, then this will happen because the underlying + // reader will return Ok(0), in which case we'll see `Ok` ourselves. In + // this case we flip the other fd back into blocking mode and read + // whatever's leftover on that file descriptor. + fn read(fd: &FileDesc, dst: &mut Vec) -> Result { + match fd.read_to_end(dst) { + Ok(_) => Ok(true), + Err(e) => { + if e.raw_os_error() == Some(libc::EWOULDBLOCK) + || e.raw_os_error() == Some(libc::EAGAIN) + { + Ok(false) + } else { + Err(e) + } + } + } + } +} diff --git a/library/std/src/sys/process/unix/mod.rs b/library/std/src/sys/process/unix/mod.rs index cda1bf74f1cad..1938e8f4b737c 100644 --- a/library/std/src/sys/process/unix/mod.rs +++ b/library/std/src/sys/process/unix/mod.rs @@ -23,5 +23,5 @@ cfg_select! { pub use imp::{ExitStatus, ExitStatusError, Process}; -pub use self::common::{Command, CommandArgs, ExitCode, Stdio}; +pub use self::common::{ChildPipe, Command, CommandArgs, ExitCode, Stdio, read_output}; pub use crate::ffi::OsString as EnvKey; diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 7d944f2f7eef1..d14caf6dc88d0 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -78,7 +78,7 @@ impl Command { let (input, output) = sys::net::Socket::new_pair(libc::AF_UNIX, libc::SOCK_SEQPACKET)?; #[cfg(not(target_os = "linux"))] - let (input, output) = sys::pipe::anon_pipe()?; + let (input, output) = sys::pipe::pipe()?; // Whatever happens after the fork is almost for sure going to touch or // look at the environment in one way or another (PATH in `execvp` or diff --git a/library/std/src/sys/process/unsupported.rs b/library/std/src/sys/process/unsupported.rs index 2dfc676ec0059..455c38e55b7ba 100644 --- a/library/std/src/sys/process/unsupported.rs +++ b/library/std/src/sys/process/unsupported.rs @@ -5,7 +5,6 @@ use crate::num::NonZero; use crate::path::Path; use crate::process::StdioPipes; use crate::sys::fs::File; -use crate::sys::pipe::AnonPipe; use crate::sys::unsupported; use crate::{fmt, io}; @@ -107,8 +106,8 @@ pub fn output(_cmd: &mut Command) -> io::Result<(ExitStatus, Vec, Vec)> unsupported() } -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { +impl From for Stdio { + fn from(pipe: ChildPipe) -> Stdio { pipe.diverge() } } @@ -317,3 +316,14 @@ impl<'a> fmt::Debug for CommandArgs<'a> { f.debug_list().entries(self.iter.clone()).finish() } } + +pub type ChildPipe = crate::sys::pipe::Pipe; + +pub fn read_output( + out: ChildPipe, + _stdout: &mut Vec, + _err: ChildPipe, + _stderr: &mut Vec, +) -> io::Result<()> { + match out.diverge() {} +} diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs index 6e8be21a1fa6d..85b9682320d28 100644 --- a/library/std/src/sys/process/windows.rs +++ b/library/std/src/sys/process/windows.rs @@ -23,11 +23,14 @@ use crate::sys::fs::{File, OpenOptions}; use crate::sys::handle::Handle; use crate::sys::pal::api::{self, WinError, utf16}; use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf}; -use crate::sys::pipe::{self, AnonPipe}; use crate::sys::{cvt, path, stdio}; use crate::sys_common::IntoInner; use crate::{cmp, env, fmt, ptr}; +mod child_pipe; + +pub use self::child_pipe::{ChildPipe, read_output}; + //////////////////////////////////////////////////////////////////////////////// // Command //////////////////////////////////////////////////////////////////////////////// @@ -167,7 +170,7 @@ pub enum Stdio { InheritSpecific { from_stdio_id: u32 }, Null, MakePipe, - Pipe(AnonPipe), + Pipe(ChildPipe), Handle(Handle), } @@ -596,7 +599,7 @@ fn program_exists(path: &Path) -> Option> { } impl Stdio { - fn to_handle(&self, stdio_id: u32, pipe: &mut Option) -> io::Result { + fn to_handle(&self, stdio_id: u32, pipe: &mut Option) -> io::Result { let use_stdio_id = |stdio_id| match stdio::get_handle(stdio_id) { Ok(io) => unsafe { let io = Handle::from_raw_handle(io); @@ -613,14 +616,15 @@ impl Stdio { Stdio::MakePipe => { let ours_readable = stdio_id != c::STD_INPUT_HANDLE; - let pipes = pipe::anon_pipe(ours_readable, true)?; + let pipes = child_pipe::child_pipe(ours_readable, true)?; *pipe = Some(pipes.ours); Ok(pipes.theirs.into_handle()) } Stdio::Pipe(ref source) => { let ours_readable = stdio_id != c::STD_INPUT_HANDLE; - pipe::spawn_pipe_relay(source, ours_readable, true).map(AnonPipe::into_handle) + child_pipe::spawn_pipe_relay(source, ours_readable, true) + .map(ChildPipe::into_handle) } Stdio::Handle(ref handle) => handle.duplicate(0, true, c::DUPLICATE_SAME_ACCESS), @@ -639,8 +643,8 @@ impl Stdio { } } -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { +impl From for Stdio { + fn from(pipe: ChildPipe) -> Stdio { Stdio::Pipe(pipe) } } diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/process/windows/child_pipe.rs similarity index 91% rename from library/std/src/sys/pal/windows/pipe.rs rename to library/std/src/sys/process/windows/child_pipe.rs index 32cf4695d4a15..6b00c54407ad5 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/process/windows/child_pipe.rs @@ -6,39 +6,37 @@ use crate::sys::{api, c}; use crate::sys_common::{FromInner, IntoInner}; use crate::{mem, ptr}; -//////////////////////////////////////////////////////////////////////////////// -// Anonymous pipes -//////////////////////////////////////////////////////////////////////////////// - -pub struct AnonPipe { +pub struct ChildPipe { inner: Handle, } -impl IntoInner for AnonPipe { +impl IntoInner for ChildPipe { fn into_inner(self) -> Handle { self.inner } } -impl FromInner for AnonPipe { - fn from_inner(inner: Handle) -> AnonPipe { +impl FromInner for ChildPipe { + fn from_inner(inner: Handle) -> ChildPipe { Self { inner } } } -pub struct Pipes { - pub ours: AnonPipe, - pub theirs: AnonPipe, +pub(super) struct Pipes { + pub ours: ChildPipe, + pub theirs: ChildPipe, } -/// Although this looks similar to `anon_pipe` in the Unix module it's actually -/// subtly different. Here we'll return two pipes in the `Pipes` return value, -/// but one is intended for "us" where as the other is intended for "someone -/// else". +/// Creates an anonymous pipe suitable for communication with a child process. /// -/// Currently the only use case for this function is pipes for stdio on -/// processes in the standard library, so "ours" is the one that'll stay in our -/// process whereas "theirs" will be inherited to a child. +/// Windows unfortunately does not have a way of performing asynchronous operations +/// on a handle originally created for synchronous operation. As `read_output` can +/// only be correctly implemented with asynchronous reads but the pipe created by +/// `CreatePipe` is synchronous, we cannot use it (and thus [`io::pipe`]) to create +/// a pipe for communicating with a child. Instead, this function uses the NT API +/// to create a pipe where one pipe handle (`ours`) is asynchronous and one is +/// synchronous and can be inherited by a child for use as a console handle +/// (`theirs`). /// /// The ours/theirs pipes are *not* specifically readable or writable. Each /// one only supports a read or a write, but which is which depends on the @@ -50,7 +48,11 @@ pub struct Pipes { /// mode. This means that technically speaking it should only ever be used /// with `OVERLAPPED` instances, but also works out ok if it's only ever used /// once at a time (which we do indeed guarantee). -pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Result { +// FIXME(joboet): No, we don't guarantee that? E.g. `&Stdout` is both `Read` +// and `Sync`, so there could be multiple operations at the same +// time. All the functions below that forward to the inner handle +// methods could abort if used concurrently. +pub(super) fn child_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Result { // A 64kb pipe capacity is the same as a typical Linux default. const PIPE_BUFFER_CAPACITY: u32 = 64 * 1024; @@ -166,7 +168,7 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res } }; - Ok(Pipes { ours: AnonPipe { inner: ours }, theirs: AnonPipe { inner: theirs } }) + Ok(Pipes { ours: ChildPipe { inner: ours }, theirs: ChildPipe { inner: theirs } }) } } @@ -175,16 +177,16 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res /// /// This is achieved by creating a new set of pipes and spawning a thread that /// relays messages between the source and the synchronous pipe. -pub fn spawn_pipe_relay( - source: &AnonPipe, +pub(super) fn spawn_pipe_relay( + source: &ChildPipe, ours_readable: bool, their_handle_inheritable: bool, -) -> io::Result { +) -> io::Result { // We need this handle to live for the lifetime of the thread spawned below. let source = source.try_clone()?; // create a new pair of anon pipes. - let Pipes { theirs, ours } = anon_pipe(ours_readable, their_handle_inheritable)?; + let Pipes { theirs, ours } = child_pipe(ours_readable, their_handle_inheritable)?; // Spawn a thread that passes messages from one pipe to the other. // Any errors will simply cause the thread to exit. @@ -210,7 +212,7 @@ pub fn spawn_pipe_relay( Ok(theirs) } -impl AnonPipe { +impl ChildPipe { pub fn handle(&self) -> &Handle { &self.inner } @@ -219,7 +221,7 @@ impl AnonPipe { } pub fn try_clone(&self) -> io::Result { - self.inner.duplicate(0, false, c::DUPLICATE_SAME_ACCESS).map(|inner| AnonPipe { inner }) + self.inner.duplicate(0, false, c::DUPLICATE_SAME_ACCESS).map(|inner| ChildPipe { inner }) } pub fn read(&self, buf: &mut [u8]) -> io::Result { @@ -347,18 +349,17 @@ impl AnonPipe { // STEP 3: The callback. unsafe extern "system" fn callback( - dwErrorCode: u32, - dwNumberOfBytesTransferred: u32, - lpOverlapped: *mut c::OVERLAPPED, + error: u32, + transferred: u32, + overlapped: *mut c::OVERLAPPED, ) { // Set `async_result` using a pointer smuggled through `hEvent`. // SAFETY: // At this point, the OVERLAPPED struct will have been written to by the OS, // except for our `hEvent` field which we set to a valid AsyncResult pointer (see below) unsafe { - let result = - AsyncResult { error: dwErrorCode, transferred: dwNumberOfBytesTransferred }; - *(*lpOverlapped).hEvent.cast::>() = Some(result); + let result = AsyncResult { error, transferred }; + *(*overlapped).hEvent.cast::>() = Some(result); } } @@ -395,7 +396,12 @@ impl AnonPipe { } } -pub fn read2(p1: AnonPipe, v1: &mut Vec, p2: AnonPipe, v2: &mut Vec) -> io::Result<()> { +pub fn read_output( + p1: ChildPipe, + v1: &mut Vec, + p2: ChildPipe, + v2: &mut Vec, +) -> io::Result<()> { let p1 = p1.into_handle(); let p2 = p2.into_handle(); diff --git a/library/std/src/sys/process/windows/tests.rs b/library/std/src/sys/process/windows/tests.rs index a21afe3363c55..bc5e0d5c7fc97 100644 --- a/library/std/src/sys/process/windows/tests.rs +++ b/library/std/src/sys/process/windows/tests.rs @@ -1,8 +1,10 @@ +use super::child_pipe::{Pipes, child_pipe}; use super::{Arg, make_command_line}; -use crate::env; use crate::ffi::{OsStr, OsString}; use crate::os::windows::io::AsHandle; use crate::process::{Command, Stdio}; +use crate::time::Duration; +use crate::{env, thread}; #[test] fn test_raw_args() { @@ -233,3 +235,26 @@ fn windows_exe_resolver() { ); } } + +/// Test the synchronous fallback for overlapped I/O. +/// +/// While technically testing `Handle` functionality, this is situated in this +/// module to allow easier access to `ChildPipe`. +#[test] +fn overlapped_handle_fallback() { + // Create some pipes. `ours` will be asynchronous. + let Pipes { ours, theirs } = child_pipe(true, false).unwrap(); + + let async_readable = ours.into_handle(); + let sync_writeable = theirs.into_handle(); + + thread::scope(|_| { + thread::sleep(Duration::from_millis(100)); + sync_writeable.write(b"hello world!").unwrap(); + }); + + // The pipe buffer starts empty so reading won't complete synchronously unless + // our fallback path works. + let mut buffer = [0u8; 1024]; + async_readable.read(&mut buffer).unwrap(); +} diff --git a/library/std/src/sys/stdio/motor.rs b/library/std/src/sys/stdio/motor.rs index 0a44feab723d0..e268bd5413df2 100644 --- a/library/std/src/sys/stdio/motor.rs +++ b/library/std/src/sys/stdio/motor.rs @@ -166,7 +166,7 @@ impl From for OwnedFd { impl From for process::ChildStdin { #[inline] fn from(fd: OwnedFd) -> process::ChildStdin { - let pipe = sys::pipe::AnonPipe::from_inner(fd); + let pipe = sys::process::ChildPipe::from_inner(fd); process::ChildStdin::from_inner(pipe) } } @@ -196,7 +196,7 @@ impl From for OwnedFd { impl From for process::ChildStdout { #[inline] fn from(fd: OwnedFd) -> process::ChildStdout { - let pipe = sys::pipe::AnonPipe::from_inner(fd); + let pipe = sys::process::ChildPipe::from_inner(fd); process::ChildStdout::from_inner(pipe) } } @@ -226,7 +226,7 @@ impl From for OwnedFd { impl From for process::ChildStderr { #[inline] fn from(fd: OwnedFd) -> process::ChildStderr { - let pipe = sys::pipe::AnonPipe::from_inner(fd); + let pipe = sys::process::ChildPipe::from_inner(fd); process::ChildStderr::from_inner(pipe) } } diff --git a/tests/run-make/branch-protection-check-IBT/lib.rs b/tests/run-make/branch-protection-check-IBT/lib.rs new file mode 100644 index 0000000000000..0c9ac1ac8e4bd --- /dev/null +++ b/tests/run-make/branch-protection-check-IBT/lib.rs @@ -0,0 +1 @@ +#![no_std] diff --git a/tests/run-make/branch-protection-check-IBT/main.rs b/tests/run-make/branch-protection-check-IBT/main.rs deleted file mode 100644 index 445b8795134c5..0000000000000 --- a/tests/run-make/branch-protection-check-IBT/main.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![feature(no_core)] -#![allow(internal_features)] -#![no_core] -#![no_std] -#![no_main] diff --git a/tests/run-make/branch-protection-check-IBT/rmake.rs b/tests/run-make/branch-protection-check-IBT/rmake.rs index 73109df12ae9d..34f0693562c0b 100644 --- a/tests/run-make/branch-protection-check-IBT/rmake.rs +++ b/tests/run-make/branch-protection-check-IBT/rmake.rs @@ -41,13 +41,19 @@ use run_make_support::{bare_rustc, llvm_readobj}; fn main() { - // `main.rs` is `#![no_std]` to not pull in the currently not-compiled-with-IBT precompiled std. + // `lib.rs` is `#![no_std]` to not pull in the currently not-compiled-with-IBT precompiled std. bare_rustc() - .input("main.rs") + .input("lib.rs") + .crate_type("lib") + .emit("obj=lib.o") .target("x86_64-unknown-linux-gnu") .arg("-Zcf-protection=branch") - .arg("-Clink-args=-nostartfiles") .run(); - llvm_readobj().arg("-nW").input("main").run().assert_stdout_contains(".note.gnu.property"); + llvm_readobj() + .arg("-nW") + .input("lib.o") + .run() + .assert_stdout_contains(".note.gnu.property") + .assert_stdout_contains("feature: IBT"); } diff --git a/tests/rustdoc-ui/invalid-cfg.stderr b/tests/rustdoc-ui/invalid-cfg.stderr index 84f8cea543145..5396110709692 100644 --- a/tests/rustdoc-ui/invalid-cfg.stderr +++ b/tests/rustdoc-ui/invalid-cfg.stderr @@ -2,7 +2,9 @@ error[E0539]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:2:1 | LL | #[doc(cfg = "x")] - | ^^^^^^^^^^^^^^^^^ expected this to be a list + | ^^^^^^^^^^-----^^ + | | + | expected this to be a list error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:3:1 @@ -16,7 +18,9 @@ error[E0539]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:7:1 | LL | #[doc(cfg = "x")] - | ^^^^^^^^^^^^^^^^^ expected this to be a list + | ^^^^^^^^^^-----^^ + | | + | expected this to be a list error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:8:1 @@ -30,7 +34,9 @@ error[E0539]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:12:1 | LL | #[doc(cfg = "x")] - | ^^^^^^^^^^^^^^^^^ expected this to be a list + | ^^^^^^^^^^-----^^ + | | + | expected this to be a list error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:13:1 @@ -44,7 +50,9 @@ error[E0539]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:18:1 | LL | #[doc(cfg = "x")] - | ^^^^^^^^^^^^^^^^^ expected this to be a list + | ^^^^^^^^^^-----^^ + | | + | expected this to be a list error[E0805]: malformed `doc` attribute input --> $DIR/invalid-cfg.rs:19:1 diff --git a/tests/ui/attributes/invalid-macro-use.rs b/tests/ui/attributes/invalid-macro-use.rs index 52e4608303f04..4d05e933647be 100644 --- a/tests/ui/attributes/invalid-macro-use.rs +++ b/tests/ui/attributes/invalid-macro-use.rs @@ -2,7 +2,9 @@ //~^ NOTE the lint level is defined here #[macro_use = 5] -//~^ ERROR valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and `#[macro_use]` +//~^ ERROR malformed `macro_use` attribute input +//~| NOTE expected a list or no arguments here +//~| NOTE for more information, visit extern crate std as s1; #[macro_use(5)] diff --git a/tests/ui/attributes/invalid-macro-use.stderr b/tests/ui/attributes/invalid-macro-use.stderr index ff3ed6196d3d3..fe235ab209f33 100644 --- a/tests/ui/attributes/invalid-macro-use.stderr +++ b/tests/ui/attributes/invalid-macro-use.stderr @@ -1,23 +1,35 @@ error[E0469]: imported macro not found - --> $DIR/invalid-macro-use.rs:51:13 + --> $DIR/invalid-macro-use.rs:53:13 | LL | #[macro_use(a)] | ^ error[E0469]: imported macro not found - --> $DIR/invalid-macro-use.rs:53:13 + --> $DIR/invalid-macro-use.rs:55:13 | LL | #[macro_use(b)] | ^ -error: valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and `#[macro_use]` +error[E0539]: malformed `macro_use` attribute input --> $DIR/invalid-macro-use.rs:4:1 | LL | #[macro_use = 5] - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^---^ + | | + | expected a list or no arguments here + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[macro_use = 5] +LL + #[macro_use(name1, name2, ...)] + | +LL - #[macro_use = 5] +LL + #[macro_use] + | error[E0539]: malformed `macro_use` attribute input - --> $DIR/invalid-macro-use.rs:8:1 + --> $DIR/invalid-macro-use.rs:10:1 | LL | #[macro_use(5)] | ^^^^^^^^^^^^-^^ @@ -35,7 +47,7 @@ LL + #[macro_use] | error[E0565]: malformed `macro_use` attribute input - --> $DIR/invalid-macro-use.rs:14:1 + --> $DIR/invalid-macro-use.rs:16:1 | LL | #[macro_use(a = "b")] | ^^^^^^^^^^^^^^-----^^ @@ -53,7 +65,7 @@ LL + #[macro_use] | error[E0565]: malformed `macro_use` attribute input - --> $DIR/invalid-macro-use.rs:20:1 + --> $DIR/invalid-macro-use.rs:22:1 | LL | #[macro_use(a(b))] | ^^^^^^^^^^^^^---^^ @@ -71,7 +83,7 @@ LL + #[macro_use] | error[E0539]: malformed `macro_use` attribute input - --> $DIR/invalid-macro-use.rs:26:1 + --> $DIR/invalid-macro-use.rs:28:1 | LL | #[macro_use(a::b)] | ^^^^^^^^^^^^----^^ @@ -89,13 +101,13 @@ LL + #[macro_use] | error: unused attribute - --> $DIR/invalid-macro-use.rs:32:1 + --> $DIR/invalid-macro-use.rs:34:1 | LL | #[macro_use(a)] | ^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/invalid-macro-use.rs:34:1 + --> $DIR/invalid-macro-use.rs:36:1 | LL | #[macro_use] | ^^^^^^^^^^^^ @@ -106,25 +118,25 @@ LL | #![deny(unused_attributes)] | ^^^^^^^^^^^^^^^^^ error: unused attribute - --> $DIR/invalid-macro-use.rs:40:1 + --> $DIR/invalid-macro-use.rs:42:1 | LL | #[macro_use(a)] | ^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/invalid-macro-use.rs:38:1 + --> $DIR/invalid-macro-use.rs:40:1 | LL | #[macro_use] | ^^^^^^^^^^^^ error: unused attribute - --> $DIR/invalid-macro-use.rs:46:1 + --> $DIR/invalid-macro-use.rs:48:1 | LL | #[macro_use] | ^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/invalid-macro-use.rs:44:1 + --> $DIR/invalid-macro-use.rs:46:1 | LL | #[macro_use] | ^^^^^^^^^^^^ diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs index 26ee89dd7b3be..37ccf9faa1a3e 100644 --- a/tests/ui/attributes/malformed-attrs.rs +++ b/tests/ui/attributes/malformed-attrs.rs @@ -59,7 +59,7 @@ #[cold = 1] //~^ ERROR malformed #[must_use()] -//~^ ERROR valid forms for the attribute are +//~^ ERROR malformed #[no_mangle = 1] //~^ ERROR malformed #[unsafe(naked())] @@ -214,12 +214,12 @@ static mut TLS: u8 = 42; #[no_link()] //~^ ERROR malformed #[macro_use = 1] -//~^ ERROR valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and `#[macro_use]` +//~^ ERROR malformed extern crate wloop; //~^ ERROR can't find crate for `wloop` [E0463] #[macro_export = 18] -//~^ ERROR valid forms for the attribute are +//~^ ERROR malformed #[allow_internal_unsafe = 1] //~^ ERROR malformed //~| ERROR allow_internal_unsafe side-steps the unsafe_code lint diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index e1ebe4ac9eab4..0cd88e2541949 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -314,11 +314,23 @@ LL | #[cold = 1] | | didn't expect any arguments here | help: must be of the form: `#[cold]` -error: valid forms for the attribute are `#[must_use = "reason"]` and `#[must_use]` +error[E0539]: malformed `must_use` attribute input --> $DIR/malformed-attrs.rs:61:1 | LL | #[must_use()] - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^--^ + | | + | didn't expect a list here + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[must_use()] +LL + #[must_use = "reason"] + | +LL - #[must_use()] +LL + #[must_use] + | error[E0565]: malformed `no_mangle` attribute input --> $DIR/malformed-attrs.rs:63:1 @@ -614,17 +626,40 @@ LL | #[non_exhaustive = 1] | | didn't expect any arguments here | help: must be of the form: `#[non_exhaustive]` -error: valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and `#[macro_use]` +error[E0539]: malformed `macro_use` attribute input --> $DIR/malformed-attrs.rs:216:1 | LL | #[macro_use = 1] - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^---^ + | | + | expected a list or no arguments here + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[macro_use = 1] +LL + #[macro_use(name1, name2, ...)] + | +LL - #[macro_use = 1] +LL + #[macro_use] + | -error: valid forms for the attribute are `#[macro_export(local_inner_macros)]` and `#[macro_export]` +error[E0539]: malformed `macro_export` attribute input --> $DIR/malformed-attrs.rs:221:1 | LL | #[macro_export = 18] - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^----^ + | | + | expected a list or no arguments here + | +help: try changing it to one of the following valid forms of the attribute + | +LL - #[macro_export = 18] +LL + #[macro_export(local_inner_macros)] + | +LL - #[macro_export = 18] +LL + #[macro_export] + | error[E0565]: malformed `allow_internal_unsafe` attribute input --> $DIR/malformed-attrs.rs:223:1 diff --git a/tests/ui/attributes/malformed-fn-align.stderr b/tests/ui/attributes/malformed-fn-align.stderr index b419df8ea2d18..ad01457d063b9 100644 --- a/tests/ui/attributes/malformed-fn-align.stderr +++ b/tests/ui/attributes/malformed-fn-align.stderr @@ -20,9 +20,9 @@ error[E0539]: malformed `rustc_align` attribute input --> $DIR/malformed-fn-align.rs:17:1 | LL | #[rustc_align = 16] - | ^^^^^^^^^^^^^^^^^^^ - | | - | expected this to be a list + | ^^^^^^^^^^^^^^----^ + | | | + | | expected this to be a list | help: must be of the form: `#[rustc_align()]` error[E0589]: invalid alignment value: not an unsuffixed integer diff --git a/tests/ui/attributes/malformed-must_use.rs b/tests/ui/attributes/malformed-must_use.rs index 4b98affa8abd3..79a1c369f8385 100644 --- a/tests/ui/attributes/malformed-must_use.rs +++ b/tests/ui/attributes/malformed-must_use.rs @@ -1,4 +1,4 @@ -#[must_use()] //~ ERROR valid forms for the attribute are `#[must_use = "reason"]` and `#[must_use]` +#[must_use()] //~ ERROR malformed struct Test; fn main() {} diff --git a/tests/ui/attributes/malformed-must_use.stderr b/tests/ui/attributes/malformed-must_use.stderr index c948ba677444f..d4797baa1b0b9 100644 --- a/tests/ui/attributes/malformed-must_use.stderr +++ b/tests/ui/attributes/malformed-must_use.stderr @@ -1,8 +1,21 @@ -error: valid forms for the attribute are `#[must_use = "reason"]` and `#[must_use]` +error[E0539]: malformed `must_use` attribute input --> $DIR/malformed-must_use.rs:1:1 | LL | #[must_use()] - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^--^ + | | + | didn't expect a list here + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[must_use()] +LL + #[must_use = "reason"] + | +LL - #[must_use()] +LL + #[must_use] + | error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/attributes/malformed-static-align.stderr b/tests/ui/attributes/malformed-static-align.stderr index e618ca8acd75b..6f5225f7278d0 100644 --- a/tests/ui/attributes/malformed-static-align.stderr +++ b/tests/ui/attributes/malformed-static-align.stderr @@ -2,9 +2,9 @@ error[E0539]: malformed `rustc_align_static` attribute input --> $DIR/malformed-static-align.rs:4:1 | LL | #[rustc_align_static = 16] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | expected this to be a list + | ^^^^^^^^^^^^^^^^^^^^^----^ + | | | + | | expected this to be a list | help: must be of the form: `#[rustc_align_static()]` error[E0589]: invalid alignment value: not an unsuffixed integer diff --git a/tests/ui/attributes/rustc_skip_during_method_dispatch.stderr b/tests/ui/attributes/rustc_skip_during_method_dispatch.stderr index 094987e944fdf..04907f5d638ef 100644 --- a/tests/ui/attributes/rustc_skip_during_method_dispatch.stderr +++ b/tests/ui/attributes/rustc_skip_during_method_dispatch.stderr @@ -11,9 +11,9 @@ error[E0539]: malformed `rustc_skip_during_method_dispatch` attribute input --> $DIR/rustc_skip_during_method_dispatch.rs:7:1 | LL | #[rustc_skip_during_method_dispatch = "array"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | expected this to be a list + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------^ + | | | + | | expected this to be a list | help: must be of the form: `#[rustc_skip_during_method_dispatch(array, boxed_slice)]` error[E0539]: malformed `rustc_skip_during_method_dispatch` attribute input diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr index e73b20f2d5d31..1be52de708e5b 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr @@ -13,9 +13,9 @@ error[E0539]: malformed `cfg` attribute input --> $DIR/cfg-attr-syntax-validation.rs:7:1 | LL | #[cfg = 10] - | ^^^^^^^^^^^ - | | - | expected this to be a list + | ^^^^^^----^ + | | | + | | expected this to be a list | help: must be of the form: `#[cfg(predicate)]` | = note: for more information, visit diff --git a/tests/ui/deprecation/deprecation-sanity.rs b/tests/ui/deprecation/deprecation-sanity.rs index 45ee91741e5a1..d1061dc1e170b 100644 --- a/tests/ui/deprecation/deprecation-sanity.rs +++ b/tests/ui/deprecation/deprecation-sanity.rs @@ -3,7 +3,7 @@ // Various checks that deprecation attributes are used correctly mod bogus_attribute_types_1 { - #[deprecated(since = "a", note = "a", reason)] //~ ERROR unknown meta item 'reason' + #[deprecated(since = "a", note = "a", reason)] //~ ERROR malformed `deprecated` attribute input [E0539] fn f1() { } #[deprecated(since = "a", note)] //~ ERROR malformed `deprecated` attribute input [E0539] diff --git a/tests/ui/deprecation/deprecation-sanity.stderr b/tests/ui/deprecation/deprecation-sanity.stderr index a96d4a0bdea88..a4dc9f23d3d2f 100644 --- a/tests/ui/deprecation/deprecation-sanity.stderr +++ b/tests/ui/deprecation/deprecation-sanity.stderr @@ -1,8 +1,10 @@ -error[E0541]: unknown meta item 'reason' - --> $DIR/deprecation-sanity.rs:6:43 +error[E0539]: malformed `deprecated` attribute input + --> $DIR/deprecation-sanity.rs:6:5 | LL | #[deprecated(since = "a", note = "a", reason)] - | ^^^^^^ expected one of `since`, `note` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^^ + | | + | valid arguments are `since` or `note` error[E0539]: malformed `deprecated` attribute input --> $DIR/deprecation-sanity.rs:9:5 @@ -86,5 +88,5 @@ LL | #[deprecated = "hello"] error: aborting due to 10 previous errors -Some errors have detailed explanations: E0538, E0539, E0541, E0565. +Some errors have detailed explanations: E0538, E0539, E0565. For more information about an error, try `rustc --explain E0538`. diff --git a/tests/ui/feature-gates/issue-43106-gating-of-macro_use.rs b/tests/ui/feature-gates/issue-43106-gating-of-macro_use.rs index 67959a3182977..274faa4495ef0 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-macro_use.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-macro_use.rs @@ -13,7 +13,7 @@ mod macro_escape { //~^ ERROR arguments to `macro_use` are not allowed here #[macro_use = "2700"] struct S; - //~^ ERROR valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and `#[macro_use]` + //~^ ERROR malformed //~| WARN cannot be used on //~| WARN previously accepted diff --git a/tests/ui/feature-gates/issue-43106-gating-of-macro_use.stderr b/tests/ui/feature-gates/issue-43106-gating-of-macro_use.stderr index 5be17e96fb15f..1aa0e8fc2830c 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-macro_use.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-macro_use.stderr @@ -16,11 +16,23 @@ error: arguments to `macro_use` are not allowed here LL | #![macro_use(my_macro)] | ^^^^^^^^^^^^^^^^^^^^^^^ -error: valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and `#[macro_use]` +error[E0539]: malformed `macro_use` attribute input --> $DIR/issue-43106-gating-of-macro_use.rs:15:5 | LL | #[macro_use = "2700"] struct S; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^--------^ + | | + | expected a list or no arguments here + | + = note: for more information, visit +help: try changing it to one of the following valid forms of the attribute + | +LL - #[macro_use = "2700"] struct S; +LL + #[macro_use(name1, name2, ...)] struct S; + | +LL - #[macro_use = "2700"] struct S; +LL + #[macro_use] struct S; + | warning: `#[macro_use]` attribute cannot be used on structs --> $DIR/issue-43106-gating-of-macro_use.rs:15:5 @@ -61,3 +73,4 @@ LL | #[macro_use] impl S { } error: aborting due to 4 previous errors; 4 warnings emitted +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/link-native-libs/link-attr-validation-early.stderr b/tests/ui/link-native-libs/link-attr-validation-early.stderr index 101df0371b542..4bf88e150f45e 100644 --- a/tests/ui/link-native-libs/link-attr-validation-early.stderr +++ b/tests/ui/link-native-libs/link-attr-validation-early.stderr @@ -10,7 +10,9 @@ error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-early.rs:3:1 | LL | #[link = "foo"] - | ^^^^^^^^^^^^^^^ expected this to be a list + | ^^^^^^^-------^ + | | + | expected this to be a list | = note: for more information, visit 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 a5f654ca0aeb5..b09431f923aaf 100644 --- a/tests/ui/link-native-libs/link-attr-validation-late.stderr +++ b/tests/ui/link-native-libs/link-attr-validation-late.stderr @@ -142,9 +142,9 @@ error[E0539]: malformed `link` attribute input --> $DIR/link-attr-validation-late.rs:24:1 | LL | #[link(name = "...", cfg = "literal")] - | ^^^^^^^^^^^^^^^^^^^^^---------------^^ - | | - | expected this to be a list + | ^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^ + | | + | expected this to be a list | = note: for more information, visit diff --git a/tests/ui/lint/dangling-pointers-from-locals.stderr b/tests/ui/lint/dangling-pointers-from-locals.stderr index 45acc74ac34e5..05ced1cdc0042 100644 --- a/tests/ui/lint/dangling-pointers-from-locals.stderr +++ b/tests/ui/lint/dangling-pointers-from-locals.stderr @@ -9,6 +9,7 @@ LL | &x | ^^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see = note: `#[warn(dangling_pointers_from_locals)]` on by default warning: function returns a dangling pointer to dropped local variable `x` @@ -24,6 +25,7 @@ LL | x | ^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: function returns a dangling pointer to dropped local variable `x` --> $DIR/dangling-pointers-from-locals.rs:24:12 @@ -38,6 +40,7 @@ LL | return y; | ^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: function returns a dangling pointer to dropped local variable `x` --> $DIR/dangling-pointers-from-locals.rs:30:5 @@ -52,6 +55,7 @@ LL | &x as *const u8 | dangling pointer created here | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: function returns a dangling pointer to dropped local variable `x` --> $DIR/dangling-pointers-from-locals.rs:37:5 @@ -66,6 +70,7 @@ LL | x as *const u8 | ^^^^^^^^^^^^^^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: function returns a dangling pointer to dropped local variable `x` --> $DIR/dangling-pointers-from-locals.rs:43:12 @@ -80,6 +85,7 @@ LL | return &mut x as *mut u8 as *const u8 as *mut u8; | dangling pointer created here | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: function returns a dangling pointer to dropped local variable `x` --> $DIR/dangling-pointers-from-locals.rs:49:5 @@ -92,6 +98,7 @@ LL | &{ x } | ^^^^^^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: function returns a dangling pointer to dropped local variable `x` --> $DIR/dangling-pointers-from-locals.rs:57:13 @@ -108,6 +115,7 @@ LL | | } | |_____________^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: function returns a dangling pointer to dropped local variable `x` --> $DIR/dangling-pointers-from-locals.rs:67:12 @@ -120,6 +128,7 @@ LL | return &x; | ^^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: function returns a dangling pointer to dropped local variable `x` --> $DIR/dangling-pointers-from-locals.rs:73:12 @@ -132,6 +141,7 @@ LL | return &mut x; | ^^^^^^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: function returns a dangling pointer to dropped local variable `x` --> $DIR/dangling-pointers-from-locals.rs:80:16 @@ -145,6 +155,7 @@ LL | return &x; | ^^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: function returns a dangling pointer to dropped local variable `x` --> $DIR/dangling-pointers-from-locals.rs:88:5 @@ -157,6 +168,7 @@ LL | &x | ^^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: function returns a dangling pointer to dropped local variable `x` --> $DIR/dangling-pointers-from-locals.rs:94:12 @@ -169,6 +181,7 @@ LL | return &x; | ^^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: closure returns a dangling pointer to dropped local variable `x` --> $DIR/dangling-pointers-from-locals.rs:101:16 @@ -181,6 +194,7 @@ LL | return &x; | ^^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: function returns a dangling pointer to dropped local variable `x` --> $DIR/dangling-pointers-from-locals.rs:113:5 @@ -194,6 +208,7 @@ LL | &x | ^^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: function returns a dangling pointer to dropped local variable `a` --> $DIR/dangling-pointers-from-locals.rs:118:5 @@ -206,6 +221,7 @@ LL | &a | ^^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: function returns a dangling pointer to dropped local variable `a` --> $DIR/dangling-pointers-from-locals.rs:123:5 @@ -218,6 +234,7 @@ LL | &a | ^^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: function returns a dangling pointer to dropped local variable `a` --> $DIR/dangling-pointers-from-locals.rs:128:5 @@ -230,6 +247,7 @@ LL | &a | ^^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: function returns a dangling pointer to dropped local variable `a` --> $DIR/dangling-pointers-from-locals.rs:133:5 @@ -242,6 +260,7 @@ LL | &a | ^^ | = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: for more information, see warning: 19 warnings emitted diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs b/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs index d892ebdf6069a..7ecee90479d2b 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/allow.rs @@ -7,7 +7,7 @@ fn main() { #[deny(dangling_pointers_from_temporaries)] { dbg!(String::new().as_ptr()); - //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + //~^ ERROR dangling pointer } S.foo() } @@ -18,6 +18,6 @@ impl S { #[warn(dangling_pointers_from_temporaries)] fn foo(self) { dbg!(String::new().as_ptr()); - //~^ WARNING a dangling pointer will be produced because the temporary `String` will be dropped + //~^ WARNING dangling pointer } } diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr index e1c12cfd1a501..a235af144e484 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr @@ -1,33 +1,33 @@ -error: a dangling pointer will be produced because the temporary `String` will be dropped +error: this creates a dangling pointer because temporary `String` is dropped at end of statement --> $DIR/allow.rs:9:28 | LL | dbg!(String::new().as_ptr()); - | ------------- ^^^^^^ this pointer will immediately be invalid + | ------------- ^^^^^^ pointer created here | | - | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `String` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice - = help: for more information, see + = help: bind the `String` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see note: the lint level is defined here --> $DIR/allow.rs:7:12 | LL | #[deny(dangling_pointers_from_temporaries)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: a dangling pointer will be produced because the temporary `String` will be dropped +warning: this creates a dangling pointer because temporary `String` is dropped at end of statement --> $DIR/allow.rs:20:28 | LL | dbg!(String::new().as_ptr()); - | ------------- ^^^^^^ this pointer will immediately be invalid + | ------------- ^^^^^^ pointer created here | | - | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `String` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice - = help: for more information, see + = help: bind the `String` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see note: the lint level is defined here --> $DIR/allow.rs:18:12 | diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs b/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs index b376582a88677..80787390176fc 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/calls.rs @@ -25,12 +25,12 @@ fn ok() { fn not_ok() { { let ptr = cstring().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + //~^ ERROR dangling pointer consume(ptr); } consume({ let ptr = cstring().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + //~^ ERROR dangling pointer ptr }); consume({ @@ -39,11 +39,11 @@ fn not_ok() { //^ FIXME: should error }); let _ptr: *const u8 = cstring().as_ptr().cast(); - //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + //~^ ERROR dangling pointer let _ptr: *const u8 = { cstring() }.as_ptr().cast(); - //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + //~^ ERROR dangling pointer let _ptr: *const u8 = { cstring().as_ptr() }.cast(); - //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + //~^ ERROR dangling pointer } fn main() { diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr index 41c6cdd0e3ef4..4e302dcc99422 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr @@ -1,72 +1,72 @@ -error: a dangling pointer will be produced because the temporary `CString` will be dropped +error: this creates a dangling pointer because temporary `CString` is dropped at end of statement --> $DIR/calls.rs:27:29 | LL | let ptr = cstring().as_ptr(); - | --------- ^^^^^^ this pointer will immediately be invalid + | --------- ^^^^^^ pointer created here | | - | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `CString` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice - = help: for more information, see + = help: bind the `CString` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see note: the lint level is defined here --> $DIR/calls.rs:1:9 | LL | #![deny(dangling_pointers_from_temporaries)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a dangling pointer will be produced because the temporary `CString` will be dropped +error: this creates a dangling pointer because temporary `CString` is dropped at end of statement --> $DIR/calls.rs:32:29 | LL | let ptr = cstring().as_ptr(); - | --------- ^^^^^^ this pointer will immediately be invalid + | --------- ^^^^^^ pointer created here | | - | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `CString` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice - = help: for more information, see + = help: bind the `CString` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `CString` will be dropped +error: this creates a dangling pointer because temporary `CString` is dropped at end of statement --> $DIR/calls.rs:41:37 | LL | let _ptr: *const u8 = cstring().as_ptr().cast(); - | --------- ^^^^^^ this pointer will immediately be invalid + | --------- ^^^^^^ pointer created here | | - | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `CString` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice - = help: for more information, see + = help: bind the `CString` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `CString` will be dropped +error: this creates a dangling pointer because temporary `CString` is dropped at end of statement --> $DIR/calls.rs:43:41 | LL | let _ptr: *const u8 = { cstring() }.as_ptr().cast(); - | ------------- ^^^^^^ this pointer will immediately be invalid + | ------------- ^^^^^^ pointer created here | | - | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `CString` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice - = help: for more information, see + = help: bind the `CString` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `CString` will be dropped +error: this creates a dangling pointer because temporary `CString` is dropped at end of statement --> $DIR/calls.rs:45:39 | LL | let _ptr: *const u8 = { cstring().as_ptr() }.cast(); - | --------- ^^^^^^ this pointer will immediately be invalid + | --------- ^^^^^^ pointer created here | | - | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `CString` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice - = help: for more information, see + = help: bind the `CString` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see error: aborting due to 5 previous errors diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs index a98378794abc4..7036019362cdd 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.rs @@ -7,12 +7,12 @@ use std::ffi::CString; macro_rules! mymacro { () => { let s = CString::new("some text").unwrap().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + //~^ ERROR dangling pointer } } fn main() { let s = CString::new("some text").unwrap().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + //~^ ERROR dangling pointer mymacro!(); } diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr index d4126ba231f76..be9f8b19545b5 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr @@ -6,39 +6,39 @@ LL | #![deny(temporary_cstring_as_ptr)] | = note: `#[warn(renamed_and_removed_lints)]` on by default -error: a dangling pointer will be produced because the temporary `CString` will be dropped +error: this creates a dangling pointer because temporary `CString` is dropped at end of statement --> $DIR/cstring-as-ptr.rs:15:48 | LL | let s = CString::new("some text").unwrap().as_ptr(); - | ---------------------------------- ^^^^^^ this pointer will immediately be invalid + | ---------------------------------- ^^^^^^ pointer created here | | - | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `CString` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice - = help: for more information, see + = help: bind the `CString` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see note: the lint level is defined here --> $DIR/cstring-as-ptr.rs:2:9 | LL | #![deny(temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: a dangling pointer will be produced because the temporary `CString` will be dropped +error: this creates a dangling pointer because temporary `CString` is dropped at end of statement --> $DIR/cstring-as-ptr.rs:9:52 | LL | let s = CString::new("some text").unwrap().as_ptr(); - | ---------------------------------- ^^^^^^ this pointer will immediately be invalid + | ---------------------------------- ^^^^^^ pointer created here | | - | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `CString` is dropped at end of statement ... LL | mymacro!(); | ---------- in this macro invocation | - = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice - = help: for more information, see + = help: bind the `CString` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see = note: this error originates in the macro `mymacro` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs index 0fb07a3f3bc97..771ddb3493449 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.rs @@ -3,9 +3,9 @@ const MAX_PATH: usize = 260; fn main() { let str1 = String::with_capacity(MAX_PATH).as_mut_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + //~^ ERROR dangling pointer let str2 = String::from("TotototototototototototototototototoT").as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + //~^ ERROR dangling pointer unsafe { std::ptr::copy_nonoverlapping(str2, str1, 30); println!("{:?}", String::from_raw_parts(str1, 30, 30)); diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr index aace55e92cf16..b8baa2bf5601a 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr @@ -1,33 +1,33 @@ -error: a dangling pointer will be produced because the temporary `String` will be dropped +error: this creates a dangling pointer because temporary `String` is dropped at end of statement --> $DIR/example-from-issue123613.rs:5:48 | LL | let str1 = String::with_capacity(MAX_PATH).as_mut_ptr(); - | ------------------------------- ^^^^^^^^^^ this pointer will immediately be invalid + | ------------------------------- ^^^^^^^^^^ pointer created here | | - | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `String` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_mut_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_mut_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice - = help: for more information, see + = help: bind the `String` to a variable such that it outlives the pointer returned by `as_mut_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see note: the lint level is defined here --> $DIR/example-from-issue123613.rs:1:9 | LL | #![deny(dangling_pointers_from_temporaries)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a dangling pointer will be produced because the temporary `String` will be dropped +error: this creates a dangling pointer because temporary `String` is dropped at end of statement --> $DIR/example-from-issue123613.rs:7:70 | LL | let str2 = String::from("TotototototototototototototototototoT").as_ptr(); - | ----------------------------------------------------- ^^^^^^ this pointer will immediately be invalid + | ----------------------------------------------------- ^^^^^^ pointer created here | | - | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `String` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice - = help: for more information, see + = help: bind the `String` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see error: aborting due to 2 previous errors diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs b/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs index a5e84d36090fc..e56bc0f433e4c 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/ext.rs @@ -26,7 +26,7 @@ impl Ext2 for *const u32 { fn main() { let _ptr1 = Vec::::new().as_ptr().dbg(); - //~^ ERROR a dangling pointer will be produced because the temporary `Vec` will be dropped + //~^ ERROR dangling pointer let _ptr2 = vec![0].as_ptr().foo(); - //~^ ERROR a dangling pointer will be produced because the temporary `Vec` will be dropped + //~^ ERROR dangling pointer } diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr index 976334ddef9c8..f780f88134f27 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr @@ -1,33 +1,33 @@ -error: a dangling pointer will be produced because the temporary `Vec` will be dropped +error: this creates a dangling pointer because temporary `Vec` is dropped at end of statement --> $DIR/ext.rs:28:35 | LL | let _ptr1 = Vec::::new().as_ptr().dbg(); - | ----------------- ^^^^^^ this pointer will immediately be invalid + | ----------------- ^^^^^^ pointer created here | | - | this `Vec` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `Vec` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `Vec` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `Vec` inside the function will not suffice - = help: for more information, see + = help: bind the `Vec` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see note: the lint level is defined here --> $DIR/ext.rs:1:9 | LL | #![deny(dangling_pointers_from_temporaries)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a dangling pointer will be produced because the temporary `Vec` will be dropped +error: this creates a dangling pointer because temporary `Vec` is dropped at end of statement --> $DIR/ext.rs:30:25 | LL | let _ptr2 = vec![0].as_ptr().foo(); - | ------- ^^^^^^ this pointer will immediately be invalid + | ------- ^^^^^^ pointer created here | | - | this `Vec` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `Vec` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `Vec` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `Vec` inside the function will not suffice - = help: for more information, see + = help: bind the `Vec` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see error: aborting due to 2 previous errors diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs b/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs index 26019b376d3a4..10666e0a82823 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.rs @@ -2,7 +2,7 @@ fn main() { vec![0u8].as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `Vec` will be dropped + //~^ ERROR dangling pointer vec![0u8].as_mut_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `Vec` will be dropped + //~^ ERROR dangling pointer } diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr index a86a69bc39a28..367dfae9e65d4 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr @@ -1,33 +1,33 @@ -error: a dangling pointer will be produced because the temporary `Vec` will be dropped +error: this creates a dangling pointer because temporary `Vec` is dropped at end of statement --> $DIR/methods.rs:4:15 | LL | vec![0u8].as_ptr(); - | --------- ^^^^^^ this pointer will immediately be invalid + | --------- ^^^^^^ pointer created here | | - | this `Vec` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `Vec` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `Vec` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `Vec` inside the function will not suffice - = help: for more information, see + = help: bind the `Vec` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see note: the lint level is defined here --> $DIR/methods.rs:1:9 | LL | #![deny(dangling_pointers_from_temporaries)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a dangling pointer will be produced because the temporary `Vec` will be dropped +error: this creates a dangling pointer because temporary `Vec` is dropped at end of statement --> $DIR/methods.rs:6:15 | LL | vec![0u8].as_mut_ptr(); - | --------- ^^^^^^^^^^ this pointer will immediately be invalid + | --------- ^^^^^^^^^^ pointer created here | | - | this `Vec` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `Vec` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_mut_ptr` the `Vec` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `Vec` to lives at least as long as the pointer returned by the call to `as_mut_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `Vec` inside the function will not suffice - = help: for more information, see + = help: bind the `Vec` to a variable such that it outlives the pointer returned by `as_mut_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see error: aborting due to 2 previous errors diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs index 1f216586ae81d..1f816996d5149 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.rs @@ -19,18 +19,18 @@ fn main() { // Call string().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + //~^ ERROR dangling pointer // MethodCall "hello".to_string().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + //~^ ERROR dangling pointer // Tup // impossible // Binary (string() + "hello").as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + //~^ ERROR dangling pointer // Path { @@ -66,7 +66,7 @@ fn main() { // If { (if true { String::new() } else { "hello".into() }).as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + //~^ ERROR dangling pointer } // Loop @@ -75,7 +75,7 @@ fn main() { break String::new(); }) .as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + //~^ ERROR dangling pointer } // Match @@ -84,7 +84,7 @@ fn main() { s => s, } .as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + //~^ ERROR dangling pointer } // Closure @@ -92,7 +92,7 @@ fn main() { // Block { string() }.as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + //~^ ERROR dangling pointer // Assign, AssignOp // impossible @@ -132,5 +132,5 @@ fn main() { // Macro vec![0u8].as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `Vec` will be dropped + //~^ ERROR dangling pointer } diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr index e8994703cabfa..be001acad7472 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr @@ -1,115 +1,115 @@ -error: a dangling pointer will be produced because the temporary `String` will be dropped +error: this creates a dangling pointer because temporary `String` is dropped at end of statement --> $DIR/temporaries.rs:21:14 | LL | string().as_ptr(); - | -------- ^^^^^^ this pointer will immediately be invalid + | -------- ^^^^^^ pointer created here | | - | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `String` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice - = help: for more information, see + = help: bind the `String` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see note: the lint level is defined here --> $DIR/temporaries.rs:2:9 | LL | #![deny(dangling_pointers_from_temporaries)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a dangling pointer will be produced because the temporary `String` will be dropped +error: this creates a dangling pointer because temporary `String` is dropped at end of statement --> $DIR/temporaries.rs:25:25 | LL | "hello".to_string().as_ptr(); - | ------------------- ^^^^^^ this pointer will immediately be invalid + | ------------------- ^^^^^^ pointer created here | | - | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `String` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice - = help: for more information, see + = help: bind the `String` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `String` will be dropped +error: this creates a dangling pointer because temporary `String` is dropped at end of statement --> $DIR/temporaries.rs:32:26 | LL | (string() + "hello").as_ptr(); - | -------------------- ^^^^^^ this pointer will immediately be invalid + | -------------------- ^^^^^^ pointer created here | | - | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `String` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice - = help: for more information, see + = help: bind the `String` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `String` will be dropped +error: this creates a dangling pointer because temporary `String` is dropped at end of statement --> $DIR/temporaries.rs:68:61 | LL | (if true { String::new() } else { "hello".into() }).as_ptr(); - | --------------------------------------------------- ^^^^^^ this pointer will immediately be invalid + | --------------------------------------------------- ^^^^^^ pointer created here | | - | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `String` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice - = help: for more information, see + = help: bind the `String` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `String` will be dropped +error: this creates a dangling pointer because temporary `String` is dropped at end of statement --> $DIR/temporaries.rs:77:10 | LL | / (loop { LL | | break String::new(); LL | | }) - | |__________- this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | |__________- this `String` is dropped at end of statement LL | .as_ptr(); - | ^^^^^^ this pointer will immediately be invalid + | ^^^^^^ pointer created here | - = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice - = help: for more information, see + = help: bind the `String` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `String` will be dropped +error: this creates a dangling pointer because temporary `String` is dropped at end of statement --> $DIR/temporaries.rs:86:10 | LL | / match string() { LL | | s => s, LL | | } - | |_________- this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | |_________- this `String` is dropped at end of statement LL | .as_ptr(); - | ^^^^^^ this pointer will immediately be invalid + | ^^^^^^ pointer created here | - = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice - = help: for more information, see + = help: bind the `String` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `String` will be dropped +error: this creates a dangling pointer because temporary `String` is dropped at end of statement --> $DIR/temporaries.rs:94:18 | LL | { string() }.as_ptr(); - | ------------ ^^^^^^ this pointer will immediately be invalid + | ------------ ^^^^^^ pointer created here | | - | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `String` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice - = help: for more information, see + = help: bind the `String` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `Vec` will be dropped +error: this creates a dangling pointer because temporary `Vec` is dropped at end of statement --> $DIR/temporaries.rs:134:15 | LL | vec![0u8].as_ptr(); - | --------- ^^^^^^ this pointer will immediately be invalid + | --------- ^^^^^^ pointer created here | | - | this `Vec` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `Vec` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `Vec` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `Vec` inside the function will not suffice - = help: for more information, see + = help: bind the `Vec` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see error: aborting due to 8 previous errors diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs index 17c3eca89e273..072ec25f4d830 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/types.rs +++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.rs @@ -19,39 +19,39 @@ fn declval() -> T { fn main() { declval::().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `CString` will be dropped + //~^ ERROR dangling pointer because temporary `CString` declval::().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `String` will be dropped + //~^ ERROR dangling pointer because temporary `String` declval::>().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `Vec` will be dropped + //~^ ERROR dangling pointer because temporary `Vec` declval::>().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `Box` will be dropped + //~^ ERROR dangling pointer because temporary `Box` declval::>().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped + //~^ ERROR dangling pointer because temporary `Box<[u8]>` declval::>().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `Box` will be dropped + //~^ ERROR dangling pointer because temporary `Box` declval::>().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `Box` will be dropped + //~^ ERROR dangling pointer because temporary `Box` declval::<[u8; 10]>().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped + //~^ ERROR dangling pointer because temporary `[u8; 10]` declval::>().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped + //~^ ERROR dangling pointer because temporary `Box<[u8; 10]>` declval::>>().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `Box>` will be dropped + //~^ ERROR dangling pointer because temporary `Box>` declval::>().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `Box` will be dropped + //~^ ERROR dangling pointer because temporary `Box` declval::>>>>().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `Box>>>` will be dropped + //~^ ERROR dangling pointer because temporary `Box>>>` declval::>().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `Cell` will be dropped + //~^ ERROR dangling pointer because temporary `Cell` declval::>().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `MaybeUninit` will be dropped + //~^ ERROR dangling pointer because temporary `MaybeUninit` declval::>().as_ptr(); - //~^ ERROR a dangling pointer will be produced because the temporary `Vec` will be dropped + //~^ ERROR dangling pointer because temporary `Vec` declval::>().get(); - //~^ ERROR a dangling pointer will be produced because the temporary `UnsafeCell` will be dropped + //~^ ERROR dangling pointer because temporary `UnsafeCell` declval::>().get(); - //~^ ERROR a dangling pointer will be produced because the temporary `SyncUnsafeCell` will be dropped + //~^ ERROR dangling pointer because temporary `SyncUnsafeCell` declval::>().as_ptr(); declval::().as_ptr(); } diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr index fab2459b53f6f..bb37c8ad211bd 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr @@ -1,228 +1,228 @@ -error: a dangling pointer will be produced because the temporary `CString` will be dropped +error: this creates a dangling pointer because temporary `CString` is dropped at end of statement --> $DIR/types.rs:21:26 | LL | declval::().as_ptr(); - | -------------------- ^^^^^^ this pointer will immediately be invalid + | -------------------- ^^^^^^ pointer created here | | - | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `CString` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice - = help: for more information, see + = help: bind the `CString` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see note: the lint level is defined here --> $DIR/types.rs:1:9 | LL | #![deny(dangling_pointers_from_temporaries)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a dangling pointer will be produced because the temporary `String` will be dropped +error: this creates a dangling pointer because temporary `String` is dropped at end of statement --> $DIR/types.rs:23:25 | LL | declval::().as_ptr(); - | ------------------- ^^^^^^ this pointer will immediately be invalid + | ------------------- ^^^^^^ pointer created here | | - | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `String` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice - = help: for more information, see + = help: bind the `String` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `Vec` will be dropped +error: this creates a dangling pointer because temporary `Vec` is dropped at end of statement --> $DIR/types.rs:25:26 | LL | declval::>().as_ptr(); - | -------------------- ^^^^^^ this pointer will immediately be invalid + | -------------------- ^^^^^^ pointer created here | | - | this `Vec` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `Vec` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `Vec` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `Vec` inside the function will not suffice - = help: for more information, see + = help: bind the `Vec` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `Box` will be dropped +error: this creates a dangling pointer because temporary `Box` is dropped at end of statement --> $DIR/types.rs:27:31 | LL | declval::>().as_ptr(); - | ------------------------- ^^^^^^ this pointer will immediately be invalid + | ------------------------- ^^^^^^ pointer created here | | - | this `Box` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `Box` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `Box` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `Box` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `Box` inside the function will not suffice - = help: for more information, see + = help: bind the `Box` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped +error: this creates a dangling pointer because temporary `Box<[u8]>` is dropped at end of statement --> $DIR/types.rs:29:28 | LL | declval::>().as_ptr(); - | ---------------------- ^^^^^^ this pointer will immediately be invalid + | ---------------------- ^^^^^^ pointer created here | | - | this `Box<[u8]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `Box<[u8]>` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `Box<[u8]>` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `Box<[u8]>` inside the function will not suffice - = help: for more information, see + = help: bind the `Box<[u8]>` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `Box` will be dropped +error: this creates a dangling pointer because temporary `Box` is dropped at end of statement --> $DIR/types.rs:31:27 | LL | declval::>().as_ptr(); - | --------------------- ^^^^^^ this pointer will immediately be invalid + | --------------------- ^^^^^^ pointer created here | | - | this `Box` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `Box` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `Box` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `Box` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `Box` inside the function will not suffice - = help: for more information, see + = help: bind the `Box` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `Box` will be dropped +error: this creates a dangling pointer because temporary `Box` is dropped at end of statement --> $DIR/types.rs:33:28 | LL | declval::>().as_ptr(); - | ---------------------- ^^^^^^ this pointer will immediately be invalid + | ---------------------- ^^^^^^ pointer created here | | - | this `Box` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `Box` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `Box` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `Box` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `Box` inside the function will not suffice - = help: for more information, see + = help: bind the `Box` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped +error: this creates a dangling pointer because temporary `[u8; 10]` is dropped at end of statement --> $DIR/types.rs:35:27 | LL | declval::<[u8; 10]>().as_ptr(); - | --------------------- ^^^^^^ this pointer will immediately be invalid + | --------------------- ^^^^^^ pointer created here | | - | this `[u8; 10]` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `[u8; 10]` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `[u8; 10]` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `[u8; 10]` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `[u8; 10]` inside the function will not suffice - = help: for more information, see + = help: bind the `[u8; 10]` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped +error: this creates a dangling pointer because temporary `Box<[u8; 10]>` is dropped at end of statement --> $DIR/types.rs:37:32 | LL | declval::>().as_ptr(); - | -------------------------- ^^^^^^ this pointer will immediately be invalid + | -------------------------- ^^^^^^ pointer created here | | - | this `Box<[u8; 10]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `Box<[u8; 10]>` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8; 10]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `Box<[u8; 10]>` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `Box<[u8; 10]>` inside the function will not suffice - = help: for more information, see + = help: bind the `Box<[u8; 10]>` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `Box>` will be dropped +error: this creates a dangling pointer because temporary `Box>` is dropped at end of statement --> $DIR/types.rs:39:31 | LL | declval::>>().as_ptr(); - | ------------------------- ^^^^^^ this pointer will immediately be invalid + | ------------------------- ^^^^^^ pointer created here | | - | this `Box>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `Box>` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `Box>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `Box>` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `Box>` inside the function will not suffice - = help: for more information, see + = help: bind the `Box>` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `Box` will be dropped +error: this creates a dangling pointer because temporary `Box` is dropped at end of statement --> $DIR/types.rs:41:30 | LL | declval::>().as_ptr(); - | ------------------------ ^^^^^^ this pointer will immediately be invalid + | ------------------------ ^^^^^^ pointer created here | | - | this `Box` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `Box` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `Box` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `Box` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `Box` inside the function will not suffice - = help: for more information, see + = help: bind the `Box` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `Box>>>` will be dropped +error: this creates a dangling pointer because temporary `Box>>>` is dropped at end of statement --> $DIR/types.rs:43:43 | LL | declval::>>>>().as_ptr(); - | ------------------------------------- ^^^^^^ this pointer will immediately be invalid + | ------------------------------------- ^^^^^^ pointer created here | | - | this `Box>>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `Box>>>` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `Box>>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `Box>>>` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `Box>>>` inside the function will not suffice - = help: for more information, see + = help: bind the `Box>>>` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `Cell` will be dropped +error: this creates a dangling pointer because temporary `Cell` is dropped at end of statement --> $DIR/types.rs:45:27 | LL | declval::>().as_ptr(); - | --------------------- ^^^^^^ this pointer will immediately be invalid + | --------------------- ^^^^^^ pointer created here | | - | this `Cell` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `Cell` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `Cell` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `Cell` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `Cell` inside the function will not suffice - = help: for more information, see + = help: bind the `Cell` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `MaybeUninit` will be dropped +error: this creates a dangling pointer because temporary `MaybeUninit` is dropped at end of statement --> $DIR/types.rs:47:34 | LL | declval::>().as_ptr(); - | ---------------------------- ^^^^^^ this pointer will immediately be invalid + | ---------------------------- ^^^^^^ pointer created here | | - | this `MaybeUninit` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `MaybeUninit` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `MaybeUninit` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `MaybeUninit` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `MaybeUninit` inside the function will not suffice - = help: for more information, see + = help: bind the `MaybeUninit` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `Vec` will be dropped +error: this creates a dangling pointer because temporary `Vec` is dropped at end of statement --> $DIR/types.rs:49:33 | LL | declval::>().as_ptr(); - | --------------------------- ^^^^^^ this pointer will immediately be invalid + | --------------------------- ^^^^^^ pointer created here | | - | this `Vec` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `Vec` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `Vec` to lives at least as long as the pointer returned by the call to `as_ptr` - = help: in particular, if this pointer is returned from the current function, binding the `Vec` inside the function will not suffice - = help: for more information, see + = help: bind the `Vec` to a variable such that it outlives the pointer returned by `as_ptr` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `UnsafeCell` will be dropped +error: this creates a dangling pointer because temporary `UnsafeCell` is dropped at end of statement --> $DIR/types.rs:51:33 | LL | declval::>().get(); - | --------------------------- ^^^ this pointer will immediately be invalid + | --------------------------- ^^^ pointer created here | | - | this `UnsafeCell` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `UnsafeCell` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `get` the `UnsafeCell` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `UnsafeCell` to lives at least as long as the pointer returned by the call to `get` - = help: in particular, if this pointer is returned from the current function, binding the `UnsafeCell` inside the function will not suffice - = help: for more information, see + = help: bind the `UnsafeCell` to a variable such that it outlives the pointer returned by `get` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see -error: a dangling pointer will be produced because the temporary `SyncUnsafeCell` will be dropped +error: this creates a dangling pointer because temporary `SyncUnsafeCell` is dropped at end of statement --> $DIR/types.rs:53:37 | LL | declval::>().get(); - | ------------------------------- ^^^ this pointer will immediately be invalid + | ------------------------------- ^^^ pointer created here | | - | this `SyncUnsafeCell` is deallocated at the end of the statement, bind it to a variable to extend its lifetime + | this `SyncUnsafeCell` is dropped at end of statement | - = note: pointers do not have a lifetime; when calling `get` the `SyncUnsafeCell` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - = help: you must make sure that the variable you bind the `SyncUnsafeCell` to lives at least as long as the pointer returned by the call to `get` - = help: in particular, if this pointer is returned from the current function, binding the `SyncUnsafeCell` inside the function will not suffice - = help: for more information, see + = help: bind the `SyncUnsafeCell` to a variable such that it outlives the pointer returned by `get` + = note: a dangling pointer is safe, but dereferencing one is undefined behavior + = note: returning a pointer to a local variable will always result in a dangling pointer + = note: for more information, see error: aborting due to 17 previous errors diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr index f46afda1e4772..2bf6ff3a9e7a9 100644 --- a/tests/ui/malformed/malformed-regressions.stderr +++ b/tests/ui/malformed/malformed-regressions.stderr @@ -10,7 +10,9 @@ error[E0539]: malformed `link` attribute input --> $DIR/malformed-regressions.rs:10:1 | LL | #[link = ""] - | ^^^^^^^^^^^^ expected this to be a list + | ^^^^^^^----^ + | | + | expected this to be a list | = note: for more information, visit diff --git a/tests/ui/proc-macro/attribute.stderr b/tests/ui/proc-macro/attribute.stderr index e7127c8ef1d2e..24962cf270a4e 100644 --- a/tests/ui/proc-macro/attribute.stderr +++ b/tests/ui/proc-macro/attribute.stderr @@ -16,7 +16,9 @@ error[E0539]: malformed `proc_macro_derive` attribute input --> $DIR/attribute.rs:15:1 | LL | #[proc_macro_derive = ""] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected this to be a list + | ^^^^^^^^^^^^^^^^^^^^----^ + | | + | expected this to be a list | = note: for more information, visit help: try changing it to one of the following valid forms of the attribute diff --git a/tests/ui/repr/repr.stderr b/tests/ui/repr/repr.stderr index e8168f8f9a582..a842590c9639e 100644 --- a/tests/ui/repr/repr.stderr +++ b/tests/ui/repr/repr.stderr @@ -10,7 +10,9 @@ error[E0539]: malformed `repr` attribute input --> $DIR/repr.rs:4:1 | LL | #[repr = "B"] - | ^^^^^^^^^^^^^ expected this to be a list + | ^^^^^^^-----^ + | | + | expected this to be a list | = note: for more information, visit @@ -18,7 +20,9 @@ error[E0539]: malformed `repr` attribute input --> $DIR/repr.rs:7:1 | LL | #[repr = "C"] - | ^^^^^^^^^^^^^ expected this to be a list + | ^^^^^^^-----^ + | | + | expected this to be a list | = note: for more information, visit diff --git a/tests/ui/sanitize-attr/invalid-sanitize.stderr b/tests/ui/sanitize-attr/invalid-sanitize.stderr index 2a3497678bdca..26ef31603d887 100644 --- a/tests/ui/sanitize-attr/invalid-sanitize.stderr +++ b/tests/ui/sanitize-attr/invalid-sanitize.stderr @@ -42,7 +42,9 @@ error[E0539]: malformed `sanitize` attribute input --> $DIR/invalid-sanitize.rs:18:1 | LL | #[sanitize = "off"] - | ^^^^^^^^^^^^^^^^^^^ expected this to be a list + | ^^^^^^^^^^^-------^ + | | + | expected this to be a list error[E0539]: malformed `sanitize` attribute input --> $DIR/invalid-sanitize.rs:21:1 diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-2.rs b/tests/ui/stability-attribute/stability-attribute-sanity-2.rs index 92e300d33d6ec..dabff97ad52dd 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity-2.rs +++ b/tests/ui/stability-attribute/stability-attribute-sanity-2.rs @@ -7,7 +7,7 @@ #[stable(feature = "a", feature = "b", since = "1.0.0")] //~ ERROR malformed `stable` attribute input [E0538] fn f1() { } -#[stable(feature = "a", sinse = "1.0.0")] //~ ERROR unknown meta item 'sinse' +#[stable(feature = "a", sinse = "1.0.0")] //~ ERROR malformed `stable` attribute input [E0539] fn f2() { } #[unstable(feature = "a", issue = "no")] diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr b/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr index 5b35a51cad729..7beb9fd979ce7 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr @@ -7,11 +7,14 @@ LL | #[stable(feature = "a", feature = "b", since = "1.0.0")] | | found `feature` used as a key more than once | help: must be of the form: `#[stable(feature = "name", since = "version")]` -error[E0541]: unknown meta item 'sinse' - --> $DIR/stability-attribute-sanity-2.rs:10:25 +error[E0539]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity-2.rs:10:1 | LL | #[stable(feature = "a", sinse = "1.0.0")] - | ^^^^^^^^^^^^^^^ expected one of `feature`, `since` + | ^^^^^^^^^^^^^^^^^^^^^^^^---------------^^ + | | | + | | valid arguments are `feature` or `since` + | help: must be of the form: `#[stable(feature = "name", since = "version")]` error[E0545]: `issue` must be a non-zero numeric string or "none" --> $DIR/stability-attribute-sanity-2.rs:13:27 @@ -23,5 +26,5 @@ LL | #[unstable(feature = "a", issue = "no")] error: aborting due to 3 previous errors -Some errors have detailed explanations: E0538, E0541, E0545. +Some errors have detailed explanations: E0538, E0539, E0545. For more information about an error, try `rustc --explain E0538`. diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-4.stderr b/tests/ui/stability-attribute/stability-attribute-sanity-4.stderr index f656aeaa16c7f..9b3f540198ce4 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity-4.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity-4.stderr @@ -11,9 +11,9 @@ error[E0539]: malformed `unstable` attribute input --> $DIR/stability-attribute-sanity-4.rs:11:5 | LL | #[unstable = "b"] - | ^^^^^^^^^^^^^^^^^ - | | - | expected this to be a list + | ^^^^^^^^^^^-----^ + | | | + | | expected this to be a list | help: must be of the form: `#[unstable(feature = "name", reason = "...", issue = "N")]` error[E0539]: malformed `stable` attribute input @@ -29,9 +29,9 @@ error[E0539]: malformed `stable` attribute input --> $DIR/stability-attribute-sanity-4.rs:17:5 | LL | #[stable = "a"] - | ^^^^^^^^^^^^^^^ - | | - | expected this to be a list + | ^^^^^^^^^-----^ + | | | + | | expected this to be a list | help: must be of the form: `#[stable(feature = "name", since = "version")]` error[E0542]: missing 'since' diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.rs b/tests/ui/stability-attribute/stability-attribute-sanity.rs index c4c86e12d267e..cee8d5fae1d2e 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.rs +++ b/tests/ui/stability-attribute/stability-attribute-sanity.rs @@ -5,7 +5,7 @@ #![stable(feature = "rust1", since = "1.0.0")] mod bogus_attribute_types_1 { - #[stable(feature = "a", since = "4.4.4", reason)] //~ ERROR unknown meta item 'reason' [E0541] + #[stable(feature = "a", since = "4.4.4", reason)] //~ ERROR malformed `stable` attribute input [E0539] fn f1() { } #[stable(feature = "a", since)] //~ ERROR malformed `stable` attribute input [E0539] diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.stderr b/tests/ui/stability-attribute/stability-attribute-sanity.stderr index ae948237d7edf..05c34484b9f86 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity.stderr @@ -1,8 +1,11 @@ -error[E0541]: unknown meta item 'reason' - --> $DIR/stability-attribute-sanity.rs:8:46 +error[E0539]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity.rs:8:5 | LL | #[stable(feature = "a", since = "4.4.4", reason)] - | ^^^^^^ expected one of `feature`, `since` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^------^^ + | | | + | | valid arguments are `feature` or `since` + | help: must be of the form: `#[stable(feature = "name", since = "version")]` error[E0539]: malformed `stable` attribute input --> $DIR/stability-attribute-sanity.rs:11:5 @@ -138,5 +141,5 @@ LL | #[stable(feature = "a", since = "1.0.0")] error: aborting due to 20 previous errors -Some errors have detailed explanations: E0539, E0541, E0542, E0543, E0544, E0546, E0547, E0549, E0711. +Some errors have detailed explanations: E0539, E0542, E0543, E0544, E0546, E0547, E0549, E0711. For more information about an error, try `rustc --explain E0539`. diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr index eaa26aa3ecafe..05a836b01af5d 100644 --- a/tests/ui/target-feature/invalid-attribute.stderr +++ b/tests/ui/target-feature/invalid-attribute.stderr @@ -26,9 +26,9 @@ error[E0539]: malformed `target_feature` attribute input --> $DIR/invalid-attribute.rs:17:1 | LL | #[target_feature = "+sse2"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | expected this to be a list + | ^^^^^^^^^^^^^^^^^---------^ + | | | + | | expected this to be a list | help: must be of the form: `#[target_feature(enable = "feat1, feat2")]` error[E0539]: malformed `target_feature` attribute input