diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index a30ab236213a0..ae3cce40f5daa 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -115,9 +115,6 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values .suggestion = remove the value -builtin_macros_derive_unsafe_path = traits in `#[derive(...)]` don't accept `unsafe(...)` - .suggestion = remove the `unsafe(...)` - builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time .cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead .custom = use `std::env::var({$var_expr})` to read the variable at run time diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index ceb62230ece96..de198115fa00b 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -6,6 +6,7 @@ use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_errors::PResult; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; +use rustc_parse::parser::attr::AllowLeadingUnsafe; use rustc_span::Span; use {rustc_ast as ast, rustc_attr as attr}; @@ -42,7 +43,7 @@ fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span })); } - let cfg = p.parse_meta_item()?; + let cfg = p.parse_meta_item(AllowLeadingUnsafe::Yes)?; let _ = p.eat(&token::Comma); diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs index 2d4a93776bb66..006b6aa823fbf 100644 --- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs +++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs @@ -47,11 +47,13 @@ impl MultiItemModifier for Expander { ) -> ExpandResult, Annotatable> { let template = AttributeTemplate { list: Some("path"), ..Default::default() }; validate_attr::check_builtin_meta_item( + &ecx.ecfg.features, &ecx.sess.psess, meta_item, ast::AttrStyle::Outer, sym::cfg_accessible, template, + true, ); let Some(path) = validate_input(ecx, meta_item) else { diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 03970a48638a0..57bddf0ab60ad 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -1,5 +1,5 @@ use rustc_ast as ast; -use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, Safety, StmtKind}; +use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; use rustc_expand::base::{ Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier, }; @@ -38,11 +38,13 @@ impl MultiItemModifier for Expander { let template = AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() }; validate_attr::check_builtin_meta_item( + features, &sess.psess, meta_item, ast::AttrStyle::Outer, sym::derive, template, + true, ); let mut resolutions = match &meta_item.kind { @@ -60,7 +62,6 @@ impl MultiItemModifier for Expander { // Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the // paths. report_path_args(sess, meta); - report_unsafe_args(sess, meta); meta.path.clone() }) .map(|path| DeriveResolution { @@ -160,13 +161,3 @@ fn report_path_args(sess: &Session, meta: &ast::MetaItem) { } } } - -fn report_unsafe_args(sess: &Session, meta: &ast::MetaItem) { - match meta.unsafety { - Safety::Unsafe(span) => { - sess.dcx().emit_err(errors::DeriveUnsafePath { span }); - } - Safety::Default => {} - Safety::Safe(_) => unreachable!(), - } -} diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 0a4f07709c7fd..93fc9bcb9d206 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -297,13 +297,6 @@ pub(crate) struct DerivePathArgsValue { pub(crate) span: Span, } -#[derive(Diagnostic)] -#[diag(builtin_macros_derive_unsafe_path)] -pub(crate) struct DeriveUnsafePath { - #[primary_span] - pub(crate) span: Span, -} - #[derive(Diagnostic)] #[diag(builtin_macros_no_default_variant)] #[help] diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs index 87187125541b2..869d203f68eba 100644 --- a/compiler/rustc_builtin_macros/src/pattern_type.rs +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -24,7 +24,7 @@ fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P let mut parser = cx.new_parser_from_tts(stream); let ty = parser.parse_ty()?; - parser.eat_keyword(sym::is); + parser.expect_keyword(sym::is)?; let pat = parser.parse_pat_no_top_alt(None, None)?; Ok((ty, pat)) diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs index 65b50736c5555..73cc8ff547d51 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -17,11 +17,13 @@ pub(crate) fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaI // All the built-in macro attributes are "words" at the moment. let template = AttributeTemplate { word: true, ..Default::default() }; validate_attr::check_builtin_meta_item( + &ecx.ecfg.features, &ecx.sess.psess, meta_item, AttrStyle::Outer, name, template, + true, ); } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 756290be0a813..f6bf9f5e89f2f 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -8,7 +8,9 @@ use rustc_ast::tokenstream::{ use rustc_ast::{self as ast, AttrStyle, Attribute, HasAttrs, HasTokens, MetaItem, NodeId}; use rustc_attr as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; -use rustc_feature::{Features, ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES}; +use rustc_feature::{ + AttributeSafety, Features, ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES, +}; use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::validate_attr; use rustc_session::parse::feature_err; @@ -263,6 +265,13 @@ impl<'a> StripUnconfigured<'a> { /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec { + validate_attr::check_attribute_safety( + self.features.unwrap_or(&Features::default()), + &self.sess.psess, + AttributeSafety::Normal, + &cfg_attr, + ); + let Some((cfg_predicate, expanded_attrs)) = rustc_parse::parse_cfg_attr(cfg_attr, &self.sess.psess) else { @@ -385,6 +394,13 @@ impl<'a> StripUnconfigured<'a> { return (true, None); } }; + + validate_attr::deny_builtin_meta_unsafety( + self.features.unwrap_or(&Features::default()), + &self.sess.psess, + &meta_item, + ); + ( parse_cfg(&meta_item, self.sess).map_or(true, |meta_item| { attr::cfg_matches(meta_item, &self.sess, self.lint_node_id, self.features) diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 886b043af2460..04e2b7d45dc93 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -15,6 +15,7 @@ use rustc_middle::ty; use rustc_middle::ty::CurrentGcx; use rustc_middle::util::Providers; use rustc_parse::new_parser_from_source_str; +use rustc_parse::parser::attr::AllowLeadingUnsafe; use rustc_query_impl::QueryCtxt; use rustc_query_system::query::print_query_stack; use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName}; @@ -67,7 +68,7 @@ pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec) -> Cfg { } match new_parser_from_source_str(&psess, filename, s.to_string()) { - Ok(mut parser) => match parser.parse_meta_item() { + Ok(mut parser) => match parser.parse_meta_item(AllowLeadingUnsafe::No) { Ok(meta_item) if parser.token == token::Eof => { if meta_item.path.segments.len() != 1 { error!("argument key must be an identifier"); @@ -173,7 +174,7 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec) -> Ch } }; - let meta_item = match parser.parse_meta_item() { + let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::Yes) { Ok(meta_item) if parser.token == token::Eof => meta_item, Ok(..) => expected_error(), Err(err) => { diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 391a57917768d..e13306b9d9fe2 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -365,6 +365,7 @@ parse_inner_doc_comment_not_permitted = expected outer doc comment .sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style parse_invalid_attr_unsafe = `{$name}` is not an unsafe attribute + .label = this is not an unsafe attribute .suggestion = remove the `unsafe(...)` .note = extraneous unsafe is not allowed in attributes diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index c5e7e0df6312e..99f2f26b8cbeb 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3183,6 +3183,7 @@ pub(crate) struct DotDotRangeAttribute { #[note] pub struct InvalidAttrUnsafe { #[primary_span] + #[label] pub span: Span, pub name: Path, } diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 12b9414d1f760..f34ef071e21ec 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -31,6 +31,12 @@ enum OuterAttributeType { Attribute, } +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum AllowLeadingUnsafe { + Yes, + No, +} + impl<'a> Parser<'a> { /// Parses attributes that appear before an item. pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> { @@ -332,7 +338,7 @@ impl<'a> Parser<'a> { /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> { - let cfg_predicate = self.parse_meta_item()?; + let cfg_predicate = self.parse_meta_item(AllowLeadingUnsafe::No)?; self.expect(&token::Comma)?; // Presumably, the majority of the time there will only be one attr. @@ -368,7 +374,10 @@ impl<'a> Parser<'a> { /// MetaItem = SimplePath ( '=' UNSUFFIXED_LIT | '(' MetaSeq? ')' )? ; /// MetaSeq = MetaItemInner (',' MetaItemInner)* ','? ; /// ``` - pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { + pub fn parse_meta_item( + &mut self, + unsafe_allowed: AllowLeadingUnsafe, + ) -> PResult<'a, ast::MetaItem> { // We can't use `maybe_whole` here because it would bump in the `None` // case, which we don't want. if let token::Interpolated(nt) = &self.token.kind @@ -384,7 +393,11 @@ impl<'a> Parser<'a> { } let lo = self.token.span; - let is_unsafe = self.eat_keyword(kw::Unsafe); + let is_unsafe = if unsafe_allowed == AllowLeadingUnsafe::Yes { + self.eat_keyword(kw::Unsafe) + } else { + false + }; let unsafety = if is_unsafe { let unsafe_span = self.prev_token.span; self.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span); @@ -427,7 +440,7 @@ impl<'a> Parser<'a> { Err(err) => err.cancel(), // we provide a better error below } - match self.parse_meta_item() { + match self.parse_meta_item(AllowLeadingUnsafe::No) { Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)), Err(err) => err.cancel(), // we provide a better error below } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index a242dc5cd582d..a4d9d97045d2a 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3153,7 +3153,8 @@ impl<'a> Parser<'a> { if !require_comma { arm_body = Some(expr); - this.eat(&token::Comma); + // Eat a comma if it exists, though. + let _ = this.eat(&token::Comma); Ok(Recovered::No) } else if let Some((span, guar)) = this.parse_arm_body_missing_braces(&expr, arrow_span) @@ -3654,7 +3655,7 @@ impl<'a> Parser<'a> { fields.push(f); } self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore); - self.eat(&token::Comma); + let _ = self.eat(&token::Comma); } } } diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index a67e3d05551db..9124c15707de5 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -178,7 +178,8 @@ impl<'a> Parser<'a> { span: this.prev_token.span, }); - this.eat(&token::Comma); + // Eat a trailing comma, if it exists. + let _ = this.eat(&token::Comma); } let param = if this.check_lifetime() { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 68da055494528..baa5eb2df635d 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1192,13 +1192,14 @@ impl<'a> Parser<'a> { mut safety: Safety, ) -> PResult<'a, ItemInfo> { let abi = self.parse_abi(); // ABI? + // FIXME: This recovery should be tested better. if safety == Safety::Default && self.token.is_keyword(kw::Unsafe) && self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Brace)) { self.expect(&token::OpenDelim(Delimiter::Brace)).unwrap_err().emit(); safety = Safety::Unsafe(self.token.span); - self.eat_keyword(kw::Unsafe); + let _ = self.eat_keyword(kw::Unsafe); } let module = ast::ForeignMod { safety, @@ -1759,7 +1760,7 @@ impl<'a> Parser<'a> { } } } - self.eat(&token::CloseDelim(Delimiter::Brace)); + self.expect(&token::CloseDelim(Delimiter::Brace))?; } else { let token_str = super::token_descr(&self.token); let where_str = if parsed_where { "" } else { "`where`, or " }; @@ -1902,7 +1903,7 @@ impl<'a> Parser<'a> { if let Some(_guar) = guar { // Handle a case like `Vec>,` where we can continue parsing fields // after the comma - self.eat(&token::Comma); + let _ = self.eat(&token::Comma); // `check_trailing_angle_brackets` already emitted a nicer error, as // proven by the presence of `_guar`. We can continue parsing. diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 26ee5bfdee42c..e01f605722b72 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -547,6 +547,7 @@ impl<'a> Parser<'a> { } #[inline] + #[must_use] fn check_noexpect(&self, tok: &TokenKind) -> bool { self.token == *tok } @@ -556,6 +557,7 @@ impl<'a> Parser<'a> { /// the main purpose of this function is to reduce the cluttering of the suggestions list /// which using the normal eat method could introduce in some cases. #[inline] + #[must_use] fn eat_noexpect(&mut self, tok: &TokenKind) -> bool { let is_present = self.check_noexpect(tok); if is_present { @@ -566,6 +568,7 @@ impl<'a> Parser<'a> { /// Consumes a token 'tok' if it exists. Returns whether the given token was present. #[inline] + #[must_use] pub fn eat(&mut self, tok: &TokenKind) -> bool { let is_present = self.check(tok); if is_present { @@ -577,12 +580,14 @@ impl<'a> Parser<'a> { /// If the next token is the given keyword, returns `true` without eating it. /// An expectation is also added for diagnostics purposes. #[inline] + #[must_use] fn check_keyword(&mut self, kw: Symbol) -> bool { self.expected_tokens.push(TokenType::Keyword(kw)); self.token.is_keyword(kw) } #[inline] + #[must_use] fn check_keyword_case(&mut self, kw: Symbol, case: Case) -> bool { if self.check_keyword(kw) { return true; @@ -602,6 +607,7 @@ impl<'a> Parser<'a> { /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes. // Public for rustc_builtin_macros and rustfmt usage. #[inline] + #[must_use] pub fn eat_keyword(&mut self, kw: Symbol) -> bool { if self.check_keyword(kw) { self.bump(); @@ -615,6 +621,7 @@ impl<'a> Parser<'a> { /// If the case differs (and is ignored) an error is issued. /// This is useful for recovery. #[inline] + #[must_use] fn eat_keyword_case(&mut self, kw: Symbol, case: Case) -> bool { if self.eat_keyword(kw) { return true; @@ -636,6 +643,7 @@ impl<'a> Parser<'a> { /// Otherwise, returns `false`. No expectation is added. // Public for rustc_builtin_macros usage. #[inline] + #[must_use] pub fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool { if self.token.is_keyword(kw) { self.bump(); @@ -648,7 +656,7 @@ impl<'a> Parser<'a> { /// If the given word is not a keyword, signals an error. /// If the next token is not the given word, signals an error. /// Otherwise, eats it. - fn expect_keyword(&mut self, kw: Symbol) -> PResult<'a, ()> { + pub fn expect_keyword(&mut self, kw: Symbol) -> PResult<'a, ()> { if !self.eat_keyword(kw) { self.unexpected() } else { Ok(()) } } @@ -1025,8 +1033,11 @@ impl<'a> Parser<'a> { f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, (ThinVec, Trailing)> { let (val, trailing, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; - if matches!(recovered, Recovered::No) { - self.eat(ket); + if matches!(recovered, Recovered::No) && !self.eat(ket) { + self.dcx().span_delayed_bug( + self.token.span, + "recovered but `parse_seq_to_before_end` did not give us the ket token", + ); } Ok((val, trailing)) } @@ -1250,7 +1261,7 @@ impl<'a> Parser<'a> { if pat { self.psess.gated_spans.gate(sym::inline_const_pat, span); } - self.eat_keyword(kw::Const); + self.expect_keyword(kw::Const)?; let (attrs, blk) = self.parse_inner_attrs_and_block()?; let anon_const = AnonConst { id: DUMMY_NODE_ID, diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index c5111226d3783..70d2c98d4f1bd 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -313,7 +313,8 @@ impl<'a> Parser<'a> { } // Generic arguments are found - `<`, `(`, `::<` or `::(`. - self.eat(&token::PathSep); + // First, eat `::` if it exists. + let _ = self.eat(&token::PathSep); let lo = self.token.span; let args = if self.eat_lt() { // `<'a, T, A = U>` diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 356bc9a410d6b..a64c00f3b6cbc 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -26,76 +26,35 @@ pub fn check_attr(features: &Features, psess: &ParseSess, attr: &Attribute) { let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); let attr_item = attr.get_normal_item(); - let is_unsafe_attr = attr_info.is_some_and(|attr| attr.safety == AttributeSafety::Unsafe); - - if features.unsafe_attributes { - if is_unsafe_attr { - if let ast::Safety::Default = attr_item.unsafety { - let path_span = attr_item.path.span; - - // If the `attr_item`'s span is not from a macro, then just suggest - // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the - // `unsafe(`, `)` right after and right before the opening and closing - // square bracket respectively. - let diag_span = if attr_item.span().can_be_used_for_suggestions() { - attr_item.span() - } else { - attr.span - .with_lo(attr.span.lo() + BytePos(2)) - .with_hi(attr.span.hi() - BytePos(1)) - }; - - if attr.span.at_least_rust_2024() { - psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe { - span: path_span, - suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion { - left: diag_span.shrink_to_lo(), - right: diag_span.shrink_to_hi(), - }, - }); - } else { - psess.buffer_lint( - UNSAFE_ATTR_OUTSIDE_UNSAFE, - path_span, - ast::CRATE_NODE_ID, - BuiltinLintDiag::UnsafeAttrOutsideUnsafe { - attribute_name_span: path_span, - sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()), - }, - ); - } - } - } else { - if let Safety::Unsafe(unsafe_span) = attr_item.unsafety { - psess.dcx().emit_err(errors::InvalidAttrUnsafe { - span: unsafe_span, - name: attr_item.path.clone(), - }); - } - } - } + // All non-builtin attributes are considered safe + let safety = attr_info.map(|x| x.safety).unwrap_or(AttributeSafety::Normal); + check_attribute_safety(features, psess, safety, attr); // Check input tokens for built-in and key-value attributes. match attr_info { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => { match parse_meta(psess, attr) { - Ok(meta) => check_builtin_meta_item(psess, &meta, attr.style, *name, *template), + // Don't check safety again, we just did that + Ok(meta) => check_builtin_meta_item( + features, psess, &meta, attr.style, *name, *template, false, + ), Err(err) => { err.emit(); } } } - _ if let AttrArgs::Eq(..) = attr_item.args => { - // All key-value attributes are restricted to meta-item syntax. - match parse_meta(psess, attr) { - Ok(_) => {} - Err(err) => { - err.emit(); + _ => { + if let AttrArgs::Eq(..) = attr_item.args { + // All key-value attributes are restricted to meta-item syntax. + match parse_meta(psess, attr) { + Ok(_) => {} + Err(err) => { + err.emit(); + } } } } - _ => {} } } @@ -198,12 +157,85 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte } } +pub fn check_attribute_safety( + features: &Features, + psess: &ParseSess, + safety: AttributeSafety, + attr: &Attribute, +) { + if !features.unsafe_attributes { + return; + } + + let attr_item = attr.get_normal_item(); + + if safety == AttributeSafety::Unsafe { + if let ast::Safety::Default = attr_item.unsafety { + let path_span = attr_item.path.span; + + // If the `attr_item`'s span is not from a macro, then just suggest + // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the + // `unsafe(`, `)` right after and right before the opening and closing + // square bracket respectively. + let diag_span = if attr_item.span().can_be_used_for_suggestions() { + attr_item.span() + } else { + attr.span.with_lo(attr.span.lo() + BytePos(2)).with_hi(attr.span.hi() - BytePos(1)) + }; + + if attr.span.at_least_rust_2024() { + psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe { + span: path_span, + suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion { + left: diag_span.shrink_to_lo(), + right: diag_span.shrink_to_hi(), + }, + }); + } else { + psess.buffer_lint( + UNSAFE_ATTR_OUTSIDE_UNSAFE, + path_span, + ast::CRATE_NODE_ID, + BuiltinLintDiag::UnsafeAttrOutsideUnsafe { + attribute_name_span: path_span, + sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()), + }, + ); + } + } + } else { + if let Safety::Unsafe(unsafe_span) = attr_item.unsafety { + psess.dcx().emit_err(errors::InvalidAttrUnsafe { + span: unsafe_span, + name: attr_item.path.clone(), + }); + } + } +} + +// Called by `check_builtin_meta_item` and code that manually denies +// `unsafe(...)` in `cfg` +pub fn deny_builtin_meta_unsafety(features: &Features, psess: &ParseSess, meta: &MetaItem) { + // This only supports denying unsafety right now - making builtin attributes + // support unsafety will requite us to thread the actual `Attribute` through + // for the nice diagnostics. + if features.unsafe_attributes { + if let Safety::Unsafe(unsafe_span) = meta.unsafety { + psess + .dcx() + .emit_err(errors::InvalidAttrUnsafe { span: unsafe_span, name: meta.path.clone() }); + } + } +} + pub fn check_builtin_meta_item( + features: &Features, psess: &ParseSess, meta: &MetaItem, style: ast::AttrStyle, name: Symbol, template: AttributeTemplate, + deny_unsafety: bool, ) { // Some special attributes like `cfg` must be checked // before the generic check, so we skip them here. @@ -212,6 +244,10 @@ pub fn check_builtin_meta_item( if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) { emit_malformed_attribute(psess, style, meta.span, name, template); } + + if deny_unsafety { + deny_builtin_meta_unsafety(features, psess, meta); + } } fn emit_malformed_attribute( diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a58c57041f830..7db958da25f2e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -461,6 +461,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => { for other_attr in attrs { + // this covers "sugared doc comments" of the form `/// ...` + // it does not cover `#[doc = "..."]`, which is handled below + if other_attr.is_doc_comment() { + continue; + } + if !ALLOW_LIST.iter().any(|name| other_attr.has_name(*name)) { self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { span: other_attr.span, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 7e5fd82b80cee..f844930ad265e 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2671,17 +2671,17 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // Store all seen lifetimes names from outer scopes. let mut seen_lifetimes = FxHashSet::default(); - // We also can't shadow bindings from the parent item - if let RibKind::AssocItem = kind { - let mut add_bindings_for_ns = |ns| { - let parent_rib = self.ribs[ns] - .iter() - .rfind(|r| matches!(r.kind, RibKind::Item(..))) - .expect("associated item outside of an item"); + // We also can't shadow bindings from associated parent items. + for ns in [ValueNS, TypeNS] { + for parent_rib in self.ribs[ns].iter().rev() { seen_bindings.extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span))); - }; - add_bindings_for_ns(ValueNS); - add_bindings_for_ns(TypeNS); + + // Break at mod level, to account for nested items which are + // allowed to shadow generic param names. + if matches!(parent_rib.kind, RibKind::Module(..)) { + break; + } + } } // Forbid shadowing lifetime bindings diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index 3acc09e0b9b1a..d690aac27fae6 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -65,4 +65,8 @@ make -C linux LLVM=1 -j$(($(nproc) + 1)) \ make -C linux LLVM=1 -j$(($(nproc) + 1)) \ samples/rust/rust_minimal.o \ samples/rust/rust_print.o \ - drivers/net/phy/ax88796b_rust.o + drivers/net/phy/ax88796b_rust.o \ + rust/doctests_kernel_generated.o + +make -C linux LLVM=1 -j$(($(nproc) + 1)) \ + rustdoc diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs index fe67aad465cdd..0cf6f1a375cdf 100644 --- a/src/tools/miri/cargo-miri/src/setup.rs +++ b/src/tools/miri/cargo-miri/src/setup.rs @@ -100,7 +100,10 @@ pub fn setup( // for target crates. let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); if env::var_os("RUSTC_STAGE").is_some() { - assert!(env::var_os("RUSTC").is_some()); + assert!( + env::var_os("RUSTC").is_some() && env::var_os("RUSTC_WRAPPER").is_some(), + "cargo-miri setup is running inside rustc bootstrap but RUSTC or RUST_WRAPPER is not set" + ); command.env("RUSTC_REAL", &cargo_miri_path); } else { command.env("RUSTC", &cargo_miri_path); diff --git a/src/tools/rustfmt/src/parse/macros/lazy_static.rs b/src/tools/rustfmt/src/parse/macros/lazy_static.rs index 7baac247e2229..b6de5f8691c25 100644 --- a/src/tools/rustfmt/src/parse/macros/lazy_static.rs +++ b/src/tools/rustfmt/src/parse/macros/lazy_static.rs @@ -33,15 +33,17 @@ pub(crate) fn parse_lazy_static( } while parser.token.kind != TokenKind::Eof { // Parse a `lazy_static!` item. + // FIXME: These `eat_*` calls should be converted to `parse_or` to avoid + // silently formatting malformed lazy-statics. let vis = parse_or!(parse_visibility, rustc_parse::parser::FollowedByType::No); - parser.eat_keyword(kw::Static); - parser.eat_keyword(kw::Ref); + let _ = parser.eat_keyword(kw::Static); + let _ = parser.eat_keyword(kw::Ref); let id = parse_or!(parse_ident); - parser.eat(&TokenKind::Colon); + let _ = parser.eat(&TokenKind::Colon); let ty = parse_or!(parse_ty); - parser.eat(&TokenKind::Eq); + let _ = parser.eat(&TokenKind::Eq); let expr = parse_or!(parse_expr); - parser.eat(&TokenKind::Semi); + let _ = parser.eat(&TokenKind::Semi); result.push((vis, id, ty, expr)); } diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs index 8ddacc07c6fd9..e2d1b85797ffe 100644 --- a/src/tools/tidy/src/error_codes.rs +++ b/src/tools/tidy/src/error_codes.rs @@ -319,7 +319,7 @@ fn check_error_codes_tests( if !found_code { verbose_print!( verbose, - "warning: Error code {code}`` has a UI test file, but doesn't contain its own error code!" + "warning: Error code `{code}` has a UI test file, but doesn't contain its own error code!" ); } } diff --git a/tests/crashes/119716-2.rs b/tests/crashes/119716-2.rs index 9cdc4417f5ba9..47bffb5c1de0d 100644 --- a/tests/crashes/119716-2.rs +++ b/tests/crashes/119716-2.rs @@ -1,4 +1,4 @@ //@ known-bug: #119716 #![feature(non_lifetime_binders)] trait Trait {} -fn f() -> impl for Trait> {} +fn f() -> impl for Trait> {} diff --git a/tests/crashes/123809.rs b/tests/crashes/123809.rs index c7a633aed018c..75abe6dc0cd83 100644 --- a/tests/crashes/123809.rs +++ b/tests/crashes/123809.rs @@ -1,4 +1,4 @@ //@ known-bug: #123809 -type Positive = std::pat::pattern_type!(std::pat:: is 0..); +type Positive = std::pat::pattern_type!(std::pat is 0..); pub fn main() {} diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 6d335ac2def1e..cb1e5c325c239 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -239,6 +239,9 @@ pub unsafe extern "C" fn compatible_target_feature() { } #[doc = "foo bar baz"] +/// a doc comment +// a normal comment +#[doc(alias = "ADocAlias")] #[naked] pub unsafe extern "C" fn compatible_doc_attributes() { asm!("", options(noreturn, raw)); diff --git a/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs b/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs index 774ce86c0960c..b8edb4aab907b 100644 --- a/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs @@ -1,6 +1,15 @@ #![feature(unsafe_attributes)] -#[derive(unsafe(Debug))] //~ ERROR: traits in `#[derive(...)]` don't accept `unsafe(...)` +#[derive(unsafe(Debug))] +//~^ ERROR: expected identifier, found keyword `unsafe` +//~| ERROR: traits in `#[derive(...)]` don't accept arguments +//~| ERROR: expected identifier, found keyword `unsafe` +//~| ERROR: expected identifier, found keyword `unsafe` +//~| ERROR: cannot find derive macro `r#unsafe` in this scope +//~| ERROR: cannot find derive macro `r#unsafe` in this scope struct Foo; +#[unsafe(derive(Debug))] //~ ERROR: is not an unsafe attribute +struct Bar; + fn main() {} diff --git a/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr index fc0daf16790a8..c40a5512fd5cd 100644 --- a/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr @@ -1,8 +1,65 @@ -error: traits in `#[derive(...)]` don't accept `unsafe(...)` +error: expected identifier, found keyword `unsafe` + --> $DIR/derive-unsafe-attributes.rs:3:10 + | +LL | #[derive(unsafe(Debug))] + | ^^^^^^ expected identifier, found keyword + | +help: escape `unsafe` to use it as an identifier + | +LL | #[derive(r#unsafe(Debug))] + | ++ + +error: traits in `#[derive(...)]` don't accept arguments + --> $DIR/derive-unsafe-attributes.rs:3:16 + | +LL | #[derive(unsafe(Debug))] + | ^^^^^^^ help: remove the arguments + +error: `derive` is not an unsafe attribute + --> $DIR/derive-unsafe-attributes.rs:12:3 + | +LL | #[unsafe(derive(Debug))] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: expected identifier, found keyword `unsafe` + --> $DIR/derive-unsafe-attributes.rs:3:10 + | +LL | #[derive(unsafe(Debug))] + | ^^^^^^ expected identifier, found keyword + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: escape `unsafe` to use it as an identifier + | +LL | #[derive(r#unsafe(Debug))] + | ++ + +error: expected identifier, found keyword `unsafe` + --> $DIR/derive-unsafe-attributes.rs:3:10 + | +LL | #[derive(unsafe(Debug))] + | ^^^^^^ expected identifier, found keyword + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: escape `unsafe` to use it as an identifier + | +LL | #[derive(r#unsafe(Debug))] + | ++ + +error: cannot find derive macro `r#unsafe` in this scope --> $DIR/derive-unsafe-attributes.rs:3:10 | LL | #[derive(unsafe(Debug))] | ^^^^^^ -error: aborting due to 1 previous error +error: cannot find derive macro `r#unsafe` in this scope + --> $DIR/derive-unsafe-attributes.rs:3:10 + | +LL | #[derive(unsafe(Debug))] + | ^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 7 previous errors diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr index ea82bac6df07b..950b2636993c1 100644 --- a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr @@ -13,7 +13,7 @@ error: `r#unsafe` is not an unsafe attribute --> $DIR/double-unsafe-attributes.rs:3:3 | LL | #[unsafe(unsafe(no_mangle))] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs new file mode 100644 index 0000000000000..0181add843bcd --- /dev/null +++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.rs @@ -0,0 +1,31 @@ +//@ edition: 2024 +//@ compile-flags: -Zunstable-options +#![feature(unsafe_attributes)] + +#[unsafe(cfg(any()))] //~ ERROR: is not an unsafe attribute +fn a() {} + +#[unsafe(cfg_attr(any(), allow(dead_code)))] //~ ERROR: is not an unsafe attribute +fn b() {} + +#[unsafe(test)] //~ ERROR: is not an unsafe attribute +fn aa() {} + +#[unsafe(ignore = "test")] //~ ERROR: is not an unsafe attribute +fn bb() {} + +#[unsafe(should_panic(expected = "test"))] //~ ERROR: is not an unsafe attribute +fn cc() {} + +#[unsafe(macro_use)] //~ ERROR: is not an unsafe attribute +mod inner { + #[unsafe(macro_export)] //~ ERROR: is not an unsafe attribute + macro_rules! m { + () => {}; + } +} + +#[unsafe(used)] //~ ERROR: is not an unsafe attribute +static FOO: usize = 0; + +fn main() {} diff --git a/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr new file mode 100644 index 0000000000000..f39074b613d40 --- /dev/null +++ b/tests/ui/attributes/unsafe/extraneous-unsafe-attributes.stderr @@ -0,0 +1,66 @@ +error: `cfg` is not an unsafe attribute + --> $DIR/extraneous-unsafe-attributes.rs:5:3 + | +LL | #[unsafe(cfg(any()))] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: `cfg_attr` is not an unsafe attribute + --> $DIR/extraneous-unsafe-attributes.rs:8:3 + | +LL | #[unsafe(cfg_attr(any(), allow(dead_code)))] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: `test` is not an unsafe attribute + --> $DIR/extraneous-unsafe-attributes.rs:11:3 + | +LL | #[unsafe(test)] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: `ignore` is not an unsafe attribute + --> $DIR/extraneous-unsafe-attributes.rs:14:3 + | +LL | #[unsafe(ignore = "test")] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: `should_panic` is not an unsafe attribute + --> $DIR/extraneous-unsafe-attributes.rs:17:3 + | +LL | #[unsafe(should_panic(expected = "test"))] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: `macro_use` is not an unsafe attribute + --> $DIR/extraneous-unsafe-attributes.rs:20:3 + | +LL | #[unsafe(macro_use)] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: `macro_export` is not an unsafe attribute + --> $DIR/extraneous-unsafe-attributes.rs:22:7 + | +LL | #[unsafe(macro_export)] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: `used` is not an unsafe attribute + --> $DIR/extraneous-unsafe-attributes.rs:28:3 + | +LL | #[unsafe(used)] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: aborting due to 8 previous errors + diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs new file mode 100644 index 0000000000000..f29a5b3252b0a --- /dev/null +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.rs @@ -0,0 +1,37 @@ +#![feature(unsafe_attributes)] + +#[unsafe(proc_macro)] +//~^ ERROR: is not an unsafe attribute +//~| ERROR attribute is only usable with crates of the `proc-macro` crate type +pub fn a() {} + + +#[unsafe(proc_macro_derive(Foo))] +//~^ ERROR: is not an unsafe attribute +//~| ERROR attribute is only usable with crates of the `proc-macro` crate type +pub fn b() {} + +#[proc_macro_derive(unsafe(Foo))] +//~^ ERROR attribute is only usable with crates of the `proc-macro` crate type +//~| ERROR: expected identifier, found keyword `unsafe` +pub fn c() {} + +#[unsafe(proc_macro_attribute)] +//~^ ERROR: is not an unsafe attribute +//~| ERROR attribute is only usable with crates of the `proc-macro` crate type +pub fn d() {} + +#[unsafe(allow(dead_code))] +//~^ ERROR: is not an unsafe attribute +pub fn e() {} + +#[unsafe(allow(unsafe(dead_code)))] +//~^ ERROR: is not an unsafe attribute +//~| ERROR: malformed lint attribute input +//~| ERROR: malformed lint attribute input +//~| ERROR: expected identifier, found keyword `unsafe` +//~| ERROR: malformed lint attribute input +//~| ERROR: malformed lint attribute input +pub fn f() {} + +fn main() {} diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr new file mode 100644 index 0000000000000..79d34d458bd6c --- /dev/null +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr @@ -0,0 +1,119 @@ +error[E0452]: malformed lint attribute input + --> $DIR/proc-unsafe-attributes.rs:28:16 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^^^^^^^^^^^^ bad attribute argument + +error[E0452]: malformed lint attribute input + --> $DIR/proc-unsafe-attributes.rs:28:16 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^^^^^^^^^^^^ bad attribute argument + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: `proc_macro` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:3:3 + | +LL | #[unsafe(proc_macro)] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: `proc_macro_derive` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:9:3 + | +LL | #[unsafe(proc_macro_derive(Foo))] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: expected identifier, found keyword `unsafe` + --> $DIR/proc-unsafe-attributes.rs:14:21 + | +LL | #[proc_macro_derive(unsafe(Foo))] + | ^^^^^^ expected identifier, found keyword + | +help: escape `unsafe` to use it as an identifier + | +LL | #[proc_macro_derive(r#unsafe(Foo))] + | ++ + +error: `proc_macro_attribute` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:19:3 + | +LL | #[unsafe(proc_macro_attribute)] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: `allow` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:24:3 + | +LL | #[unsafe(allow(dead_code))] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: `allow` is not an unsafe attribute + --> $DIR/proc-unsafe-attributes.rs:28:3 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +error: expected identifier, found keyword `unsafe` + --> $DIR/proc-unsafe-attributes.rs:28:16 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^ expected identifier, found keyword + | +help: escape `unsafe` to use it as an identifier + | +LL | #[unsafe(allow(r#unsafe(dead_code)))] + | ++ + +error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type + --> $DIR/proc-unsafe-attributes.rs:3:1 + | +LL | #[unsafe(proc_macro)] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type + --> $DIR/proc-unsafe-attributes.rs:9:1 + | +LL | #[unsafe(proc_macro_derive(Foo))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type + --> $DIR/proc-unsafe-attributes.rs:14:1 + | +LL | #[proc_macro_derive(unsafe(Foo))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the `#[proc_macro_attribute]` attribute is only usable with crates of the `proc-macro` crate type + --> $DIR/proc-unsafe-attributes.rs:19:1 + | +LL | #[unsafe(proc_macro_attribute)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0452]: malformed lint attribute input + --> $DIR/proc-unsafe-attributes.rs:28:16 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^^^^^^^^^^^^ bad attribute argument + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0452]: malformed lint attribute input + --> $DIR/proc-unsafe-attributes.rs:28:16 + | +LL | #[unsafe(allow(unsafe(dead_code)))] + | ^^^^^^^^^^^^^^^^^ bad attribute argument + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 15 previous errors + +For more information about this error, try `rustc --explain E0452`. diff --git a/tests/ui/attributes/unsafe/unsafe-attributes.rs b/tests/ui/attributes/unsafe/unsafe-attributes.rs index e7620a18048e4..5aaaa512be9cd 100644 --- a/tests/ui/attributes/unsafe/unsafe-attributes.rs +++ b/tests/ui/attributes/unsafe/unsafe-attributes.rs @@ -4,4 +4,13 @@ #[unsafe(no_mangle)] fn a() {} +#[unsafe(export_name = "foo")] +fn b() {} + +#[unsafe(link_section = ".example_section")] +static VAR1: u32 = 1; + +#[cfg_attr(any(), unsafe(no_mangle))] +static VAR2: u32 = 1; + fn main() {} diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr b/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr index 0602af34e4f64..584b0ea797d0a 100644 --- a/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr +++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr @@ -2,7 +2,7 @@ error: `repr` is not an unsafe attribute --> $DIR/unsafe-safe-attribute.rs:3:3 | LL | #[unsafe(repr(C))] - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr index 584dacf4d8c91..26b5e4e37b931 100644 --- a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr +++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr @@ -2,7 +2,7 @@ error: `diagnostic::on_unimplemented` is not an unsafe attribute --> $DIR/unsafe-safe-attribute_diagnostic.rs:3:3 | LL | #[unsafe(diagnostic::on_unimplemented( - | ^^^^^^ + | ^^^^^^ this is not an unsafe attribute | = note: extraneous unsafe is not allowed in attributes diff --git a/tests/ui/backtrace/synchronized-panic-handler.rs b/tests/ui/backtrace/synchronized-panic-handler.rs index 00eb249da1dd5..29431ae3c458a 100644 --- a/tests/ui/backtrace/synchronized-panic-handler.rs +++ b/tests/ui/backtrace/synchronized-panic-handler.rs @@ -3,6 +3,7 @@ //@ edition:2021 //@ exec-env:RUST_BACKTRACE=0 //@ needs-threads +//@ needs-unwind use std::thread; const PANIC_MESSAGE: &str = "oops oh no woe is me"; diff --git a/tests/ui/backtrace/synchronized-panic-handler.run.stderr b/tests/ui/backtrace/synchronized-panic-handler.run.stderr index b7c815a94c868..8a06d00ea5998 100644 --- a/tests/ui/backtrace/synchronized-panic-handler.run.stderr +++ b/tests/ui/backtrace/synchronized-panic-handler.run.stderr @@ -1,5 +1,5 @@ -thread '' panicked at $DIR/synchronized-panic-handler.rs:10:5: +thread '' panicked at $DIR/synchronized-panic-handler.rs:11:5: oops oh no woe is me note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread '' panicked at $DIR/synchronized-panic-handler.rs:10:5: +thread '' panicked at $DIR/synchronized-panic-handler.rs:11:5: oops oh no woe is me diff --git a/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.rs b/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.rs index 4ba696f4ae080..9f20cf0857947 100644 --- a/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.rs +++ b/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.rs @@ -9,9 +9,10 @@ fn bug(&self) where for [(); COT::BYTES]:, //~^ ERROR only lifetime parameters can be used in this context - //~^^ ERROR defaults for generic parameters are not allowed in `for<...>` binders - //~^^^ ERROR defaults for generic parameters are not allowed in `for<...>` binders - //~^^^^ ERROR failed to resolve: use of undeclared type `COT` + //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders + //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders + //~| ERROR failed to resolve: use of undeclared type `COT` + //~| ERROR the name `N` is already used for a generic parameter in this item's generic parameters { } diff --git a/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.stderr b/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.stderr index ee0ec38ab0631..6037e685e44d7 100644 --- a/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.stderr +++ b/tests/ui/const-generics/generic_const_exprs/ice-predicates-of-no-entry-found-for-key-119275.stderr @@ -6,6 +6,15 @@ LL | fn bug(&self) | = note: associated functions are those in `impl` or `trait` definitions +error[E0403]: the name `N` is already used for a generic parameter in this item's generic parameters + --> $DIR/ice-predicates-of-no-entry-found-for-key-119275.rs:10:15 + | +LL | fn bug(&self) + | - first use of `N` +... +LL | for [(); COT::BYTES]:, + | ^ already used + error[E0412]: cannot find type `Nat` in this scope --> $DIR/ice-predicates-of-no-entry-found-for-key-119275.rs:6:17 | @@ -40,7 +49,7 @@ error[E0433]: failed to resolve: use of undeclared type `COT` LL | for [(); COT::BYTES]:, | ^^^ use of undeclared type `COT` -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0412, E0433, E0658. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0403, E0412, E0433, E0658. +For more information about an error, try `rustc --explain E0403`. diff --git a/tests/ui/traits/non_lifetime_binders/shadowed.rs b/tests/ui/traits/non_lifetime_binders/shadowed.rs new file mode 100644 index 0000000000000..1c480e3940b89 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/shadowed.rs @@ -0,0 +1,18 @@ +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +fn function() where for (): Sized {} +//~^ ERROR the name `T` is already used for a generic parameter + +struct Struct(T) where for (): Sized; +//~^ ERROR the name `T` is already used for a generic parameter + +impl Struct { + fn method() where for (): Sized {} + //~^ ERROR the name `T` is already used for a generic parameter +} + +fn repeated() where for (): Sized {} +//~^ ERROR the name `T` is already used for a generic parameter + +fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/shadowed.stderr b/tests/ui/traits/non_lifetime_binders/shadowed.stderr new file mode 100644 index 0000000000000..59a073aefc961 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/shadowed.stderr @@ -0,0 +1,44 @@ +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters + --> $DIR/shadowed.rs:4:28 + | +LL | fn function() where for (): Sized {} + | - ^ already used + | | + | first use of `T` + +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters + --> $DIR/shadowed.rs:7:31 + | +LL | struct Struct(T) where for (): Sized; + | - ^ already used + | | + | first use of `T` + +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters + --> $DIR/shadowed.rs:11:27 + | +LL | impl Struct { + | - first use of `T` +LL | fn method() where for (): Sized {} + | ^ already used + +error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters + --> $DIR/shadowed.rs:15:28 + | +LL | fn repeated() where for (): Sized {} + | - ^ already used + | | + | first use of `T` + +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/shadowed.rs:1:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: aborting due to 4 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0403`. diff --git a/tests/ui/type/pattern_types/missing-is.rs b/tests/ui/type/pattern_types/missing-is.rs new file mode 100644 index 0000000000000..2fbcc1908efcb --- /dev/null +++ b/tests/ui/type/pattern_types/missing-is.rs @@ -0,0 +1,8 @@ +#![feature(core_pattern_type, core_pattern_types)] + +use std::pat::pattern_type; + +fn main() { + let x: pattern_type!(i32 0..1); + //~^ ERROR expected one of `!`, `(`, `+`, `::`, `<`, or `is`, found `0` +} diff --git a/tests/ui/type/pattern_types/missing-is.stderr b/tests/ui/type/pattern_types/missing-is.stderr new file mode 100644 index 0000000000000..8ed654fe9071a --- /dev/null +++ b/tests/ui/type/pattern_types/missing-is.stderr @@ -0,0 +1,8 @@ +error: expected one of `!`, `(`, `+`, `::`, `<`, or `is`, found `0` + --> $DIR/missing-is.rs:6:30 + | +LL | let x: pattern_type!(i32 0..1); + | ^ expected one of `!`, `(`, `+`, `::`, `<`, or `is` + +error: aborting due to 1 previous error +