diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 9ebf4c1793dde..066e3e9eceb2e 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -233,8 +233,13 @@ pub enum AttributeKind { /// Represents `#[rustc_macro_transparency]`. MacroTransparency(Transparency), + + /// Represents [`#[may_dangle]`](https://std-dev-guide.rust-lang.org/tricky/may-dangle.html). + MayDangle(Span), + /// Represents `#[optimize(size|speed)]` Optimize(OptimizeAttr, Span), + /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr(ThinVec<(ReprAttr, Span)>), diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 78a696afa2738..1bb5edba326c9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -34,6 +34,7 @@ pub(crate) mod deprecation; pub(crate) mod inline; pub(crate) mod lint_helpers; pub(crate) mod repr; +pub(crate) mod semantics; pub(crate) mod stability; pub(crate) mod transparency; pub(crate) mod util; diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs new file mode 100644 index 0000000000000..071574a5612aa --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs @@ -0,0 +1,19 @@ +use rustc_attr_data_structures::AttributeKind; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Symbol, sym}; + +use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; + +pub(crate) struct MayDangleParser; +impl SingleAttributeParser for MayDangleParser { + const PATH: &[Symbol] = &[sym::may_dangle]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn; + const TEMPLATE: AttributeTemplate = template!(Word); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option { + Some(AttributeKind::MayDangle(cx.attr_span)) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 8311fccacd894..1bcf500459d94 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -21,6 +21,7 @@ use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; use crate::attributes::lint_helpers::AsPtrParser; use crate::attributes::repr::{AlignParser, ReprParser}; +use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, }; @@ -110,6 +111,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index d32e6f1558e47..c5d1f2ad2de8c 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -104,6 +104,8 @@ builtin_macros_concat_bytes_bad_repeat = repeat count is not a positive number builtin_macros_concat_bytes_invalid = cannot concatenate {$lit_kind} literals .byte_char = try using a byte character .byte_str = try using a byte string + .c_str = try using a null-terminated byte string + .c_str_note = concatenating C strings is ambiguous about including the '\0' .number_array = try wrapping the number in an array builtin_macros_concat_bytes_missing_literal = expected a byte literal diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 456f2b9ab31de..92d011fb9d1f0 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -1,6 +1,6 @@ use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{ExprKind, LitIntType, LitKind, UintTy, token}; +use rustc_ast::{ExprKind, LitIntType, LitKind, StrStyle, UintTy, token}; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_session::errors::report_lit_error; use rustc_span::{ErrorGuaranteed, Span}; @@ -21,15 +21,32 @@ fn invalid_type_err( let snippet = cx.sess.source_map().span_to_snippet(span).ok(); let dcx = cx.dcx(); match LitKind::from_token_lit(token_lit) { - Ok(LitKind::CStr(_, _)) => { + Ok(LitKind::CStr(_, style)) => { // Avoid ambiguity in handling of terminal `NUL` by refusing to // concatenate C string literals as bytes. - dcx.emit_err(errors::ConcatCStrLit { span }) + let sugg = if let Some(mut as_bstr) = snippet + && style == StrStyle::Cooked + && as_bstr.starts_with('c') + && as_bstr.ends_with('"') + { + // Suggest`c"foo"` -> `b"foo\0"` if we can + as_bstr.replace_range(0..1, "b"); + as_bstr.pop(); + as_bstr.push_str(r#"\0""#); + Some(ConcatBytesInvalidSuggestion::CStrLit { span, as_bstr }) + } else { + // No suggestion for a missing snippet, raw strings, or if for some reason we have + // a span that doesn't match `c"foo"` (possible if a proc macro assigns a span + // that doesn't actually point to a C string). + None + }; + // We can only provide a suggestion if we have a snip and it is not a raw string + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "C string", sugg, cs_note: Some(()) }) } Ok(LitKind::Char(_)) => { let sugg = snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet }); - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg }) + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg, cs_note: None }) } Ok(LitKind::Str(_, _)) => { // suggestion would be invalid if we are nested @@ -38,18 +55,21 @@ fn invalid_type_err( } else { None }; - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg }) + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg, cs_note: None }) } Ok(LitKind::Float(_, _)) => { - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None }) - } - Ok(LitKind::Bool(_)) => { - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None }) + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None, cs_note: None }) } + Ok(LitKind::Bool(_)) => dcx.emit_err(ConcatBytesInvalid { + span, + lit_kind: "boolean", + sugg: None, + cs_note: None, + }), Ok(LitKind::Int(_, _)) if !is_nested => { let sugg = snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span, snippet }); - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg }) + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg, cs_note: None }) } Ok(LitKind::Int(val, LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8))) => { assert!(val.get() > u8::MAX.into()); // must be an error diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 3a2e96a5e5af4..b7ecfd2285ce0 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -215,6 +215,8 @@ pub(crate) struct ConcatBytesInvalid { pub(crate) lit_kind: &'static str, #[subdiagnostic] pub(crate) sugg: Option, + #[note(builtin_macros_c_str_note)] + pub(crate) cs_note: Option<()>, } #[derive(Subdiagnostic)] @@ -239,6 +241,13 @@ pub(crate) enum ConcatBytesInvalidSuggestion { span: Span, snippet: String, }, + #[note(builtin_macros_c_str_note)] + #[suggestion(builtin_macros_c_str, code = "{as_bstr}", applicability = "machine-applicable")] + CStrLit { + #[primary_span] + span: Span, + as_bstr: String, + }, #[suggestion( builtin_macros_number_array, code = "[{snippet}]", diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 37010700fab81..3ba40859d4582 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -86,7 +86,7 @@ macro_rules! ast_fragments { } } - fn make_from<'a>(self, result: Box) -> Option { + fn make_from(self, result: Box) -> Option { match self { AstFragmentKind::OptExpr => result.make_expr().map(Some).map(AstFragment::OptExpr), @@ -136,7 +136,7 @@ macro_rules! ast_fragments { T::fragment_to_output(self) } - pub(crate) fn mut_visit_with(&mut self, vis: &mut F) { + pub(crate) fn mut_visit_with(&mut self, vis: &mut impl MutVisitor) { match self { AstFragment::OptExpr(opt_expr) => { if let Some(expr) = opt_expr.take() { @@ -316,9 +316,9 @@ impl AstFragmentKind { } } - pub(crate) fn expect_from_annotatables>( + pub(crate) fn expect_from_annotatables( self, - items: I, + items: impl IntoIterator, ) -> AstFragment { let mut items = items.into_iter(); match self { @@ -1218,10 +1218,10 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized { fn descr() -> &'static str { unreachable!() } - fn walk_flat_map(self, _visitor: &mut V) -> Self::OutputTy { + fn walk_flat_map(self, _collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { unreachable!() } - fn walk(&mut self, _visitor: &mut V) { + fn walk(&mut self, _collector: &mut InvocationCollector<'_, '_>) { unreachable!() } fn is_mac_call(&self) -> bool { @@ -1276,8 +1276,8 @@ impl InvocationCollectorNode for P { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_items() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_item(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_item(collector, self) } fn is_mac_call(&self) -> bool { matches!(self.kind, ItemKind::MacCall(..)) @@ -1431,8 +1431,8 @@ impl InvocationCollectorNode for AstNodeWrapper, TraitItemTag> fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_trait_items() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Trait) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_assoc_item(collector, self.wrapped, AssocCtxt::Trait) } fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) @@ -1472,8 +1472,8 @@ impl InvocationCollectorNode for AstNodeWrapper, ImplItemTag> fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_impl_items() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Impl { of_trait: false }) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_assoc_item(collector, self.wrapped, AssocCtxt::Impl { of_trait: false }) } fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) @@ -1513,8 +1513,8 @@ impl InvocationCollectorNode for AstNodeWrapper, TraitImplItem fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_trait_impl_items() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_assoc_item(visitor, self.wrapped, AssocCtxt::Impl { of_trait: true }) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_assoc_item(collector, self.wrapped, AssocCtxt::Impl { of_trait: true }) } fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, AssocItemKind::MacCall(..)) @@ -1551,8 +1551,8 @@ impl InvocationCollectorNode for P { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_foreign_items() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_foreign_item(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_foreign_item(collector, self) } fn is_mac_call(&self) -> bool { matches!(self.kind, ForeignItemKind::MacCall(..)) @@ -1573,8 +1573,8 @@ impl InvocationCollectorNode for ast::Variant { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_variants() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_variant(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_variant(collector, self) } } @@ -1586,8 +1586,8 @@ impl InvocationCollectorNode for ast::WherePredicate { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_where_predicates() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_where_predicate(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_where_predicate(collector, self) } } @@ -1599,8 +1599,8 @@ impl InvocationCollectorNode for ast::FieldDef { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_field_defs() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_field_def(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_field_def(collector, self) } } @@ -1612,8 +1612,8 @@ impl InvocationCollectorNode for ast::PatField { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_pat_fields() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_pat_field(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_pat_field(collector, self) } } @@ -1625,8 +1625,8 @@ impl InvocationCollectorNode for ast::ExprField { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_expr_fields() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_expr_field(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_expr_field(collector, self) } } @@ -1638,8 +1638,8 @@ impl InvocationCollectorNode for ast::Param { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_params() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_param(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_param(collector, self) } } @@ -1651,8 +1651,8 @@ impl InvocationCollectorNode for ast::GenericParam { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_generic_params() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_generic_param(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_generic_param(collector, self) } } @@ -1664,8 +1664,8 @@ impl InvocationCollectorNode for ast::Arm { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_arms() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_arm(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_arm(collector, self) } } @@ -1677,8 +1677,8 @@ impl InvocationCollectorNode for ast::Stmt { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_stmts() } - fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { - walk_flat_map_stmt(visitor, self) + fn walk_flat_map(self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_flat_map_stmt(collector, self) } fn is_mac_call(&self) -> bool { match &self.kind { @@ -1751,8 +1751,8 @@ impl InvocationCollectorNode for ast::Crate { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_crate() } - fn walk(&mut self, visitor: &mut V) { - walk_crate(visitor, self) + fn walk(&mut self, collector: &mut InvocationCollector<'_, '_>) { + walk_crate(collector, self) } fn expand_cfg_false( &mut self, @@ -1777,8 +1777,8 @@ impl InvocationCollectorNode for ast::Ty { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_ty() } - fn walk(&mut self, visitor: &mut V) { - walk_ty(visitor, self) + fn walk(&mut self, collector: &mut InvocationCollector<'_, '_>) { + walk_ty(collector, self) } fn is_mac_call(&self) -> bool { matches!(self.kind, ast::TyKind::MacCall(..)) @@ -1800,8 +1800,8 @@ impl InvocationCollectorNode for ast::Pat { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_pat() } - fn walk(&mut self, visitor: &mut V) { - walk_pat(visitor, self) + fn walk(&mut self, collector: &mut InvocationCollector<'_, '_>) { + walk_pat(collector, self) } fn is_mac_call(&self) -> bool { matches!(self.kind, PatKind::MacCall(..)) @@ -1826,8 +1826,8 @@ impl InvocationCollectorNode for ast::Expr { fn descr() -> &'static str { "an expression" } - fn walk(&mut self, visitor: &mut V) { - walk_expr(visitor, self) + fn walk(&mut self, collector: &mut InvocationCollector<'_, '_>) { + walk_expr(collector, self) } fn is_mac_call(&self) -> bool { matches!(self.kind, ExprKind::MacCall(..)) @@ -1850,8 +1850,8 @@ impl InvocationCollectorNode for AstNodeWrapper, OptExprTag> { fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { fragment.make_opt_expr() } - fn walk_flat_map(mut self, visitor: &mut V) -> Self::OutputTy { - walk_expr(visitor, &mut self.wrapped); + fn walk_flat_map(mut self, collector: &mut InvocationCollector<'_, '_>) -> Self::OutputTy { + walk_expr(collector, &mut self.wrapped); Some(self.wrapped) } fn is_mac_call(&self) -> bool { @@ -1885,8 +1885,8 @@ impl InvocationCollectorNode for AstNodeWrapper, MethodReceiverTag> fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { AstNodeWrapper::new(fragment.make_method_receiver_expr(), MethodReceiverTag) } - fn walk(&mut self, visitor: &mut V) { - walk_expr(visitor, &mut self.wrapped) + fn walk(&mut self, collector: &mut InvocationCollector<'_, '_>) { + walk_expr(collector, &mut self.wrapped) } fn is_mac_call(&self) -> bool { matches!(self.wrapped.kind, ast::ExprKind::MacCall(..)) diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 556f50a85af7d..1a526d5bce0bb 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1302,6 +1302,7 @@ impl AttributeExt for Attribute { // FIXME: should not be needed anymore when all attrs are parsed Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span, Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span, + Attribute::Parsed(AttributeKind::MayDangle(span)) => *span, a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5fb9514e5caff..d0630383477b4 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -163,6 +163,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => { self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target) } + &Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => { + self.check_may_dangle(hir_id, attr_span) + } Attribute::Unparsed(_) => { match attr.path().as_slice() { [sym::diagnostic, sym::do_not_recommend, ..] => { @@ -236,7 +239,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), [sym::must_use, ..] => self.check_must_use(hir_id, attr, target), - [sym::may_dangle, ..] => self.check_may_dangle(hir_id, attr), [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target), [sym::rustc_allow_incoherent_impl, ..] => { self.check_allow_incoherent_impl(attr, span, target) @@ -1619,7 +1621,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[may_dangle]` is applied to a lifetime or type generic parameter in `Drop` impl. - fn check_may_dangle(&self, hir_id: HirId, attr: &Attribute) { + fn check_may_dangle(&self, hir_id: HirId, attr_span: Span) { if let hir::Node::GenericParam(param) = self.tcx.hir_node(hir_id) && matches!( param.kind, @@ -1636,7 +1638,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; } - self.dcx().emit_err(errors::InvalidMayDangle { attr_span: attr.span() }); + self.dcx().emit_err(errors::InvalidMayDangle { attr_span }); } /// Checks if `#[cold]` is applied to a non-function. diff --git a/tests/ui/macros/concat-bytes-error.rs b/tests/ui/macros/concat-bytes-error.rs index db5d3cab0bd8a..8130fc54d8d51 100644 --- a/tests/ui/macros/concat-bytes-error.rs +++ b/tests/ui/macros/concat-bytes-error.rs @@ -1,20 +1,44 @@ +//@ edition: 2021 +// 2021 edition for C string literals + #![feature(concat_bytes)] fn main() { + // Identifiers concat_bytes!(pie); //~ ERROR expected a byte literal concat_bytes!(pie, pie); //~ ERROR expected a byte literal + + // String literals concat_bytes!("tnrsi", "tnri"); //~ ERROR cannot concatenate string literals + //~^ SUGGESTION b"tnrsi" + concat_bytes!(r"tnrsi", r"tnri"); //~ ERROR cannot concatenate string literals + //~^ SUGGESTION br"tnrsi" + concat_bytes!(r#"tnrsi"#, r###"tnri"###); //~ ERROR cannot concatenate string literals + //~^ SUGGESTION br#"tnrsi"# + concat_bytes!(c"tnrsi", c"tnri"); //~ ERROR cannot concatenate C string literals + //~^ SUGGESTION b"tnrsi\0" + concat_bytes!(cr"tnrsi", cr"tnri"); //~ ERROR cannot concatenate C string literals + concat_bytes!(cr#"tnrsi"#, cr###"tnri"###); //~ ERROR cannot concatenate C string literals + + // Other literals concat_bytes!(2.8); //~ ERROR cannot concatenate float literals concat_bytes!(300); //~ ERROR cannot concatenate numeric literals + //~^ SUGGESTION [300] concat_bytes!('a'); //~ ERROR cannot concatenate character literals + //~^ SUGGESTION b'a' concat_bytes!(true, false); //~ ERROR cannot concatenate boolean literals concat_bytes!(42, b"va", b'l'); //~ ERROR cannot concatenate numeric literals + //~^ SUGGESTION [42] concat_bytes!(42, b"va", b'l', [1, 2]); //~ ERROR cannot concatenate numeric literals + //~^ SUGGESTION [42] + + // Nested items concat_bytes!([ "hi", //~ ERROR cannot concatenate string literals ]); concat_bytes!([ 'a', //~ ERROR cannot concatenate character literals + //~^ SUGGESTION b'a' ]); concat_bytes!([ true, //~ ERROR cannot concatenate boolean literals @@ -38,6 +62,7 @@ fn main() { [5, 6, 7], //~ ERROR cannot concatenate doubly nested array ]); concat_bytes!(5u16); //~ ERROR cannot concatenate numeric literals + //~^ SUGGESTION [5u16] concat_bytes!([5u16]); //~ ERROR numeric literal is not a `u8` concat_bytes!([3; ()]); //~ ERROR repeat count is not a positive number concat_bytes!([3; -2]); //~ ERROR repeat count is not a positive number diff --git a/tests/ui/macros/concat-bytes-error.stderr b/tests/ui/macros/concat-bytes-error.stderr index 3f2c64922e34d..447d7a663fdc0 100644 --- a/tests/ui/macros/concat-bytes-error.stderr +++ b/tests/ui/macros/concat-bytes-error.stderr @@ -1,5 +1,5 @@ error: expected a byte literal - --> $DIR/concat-bytes-error.rs:4:19 + --> $DIR/concat-bytes-error.rs:8:19 | LL | concat_bytes!(pie); | ^^^ @@ -7,7 +7,7 @@ LL | concat_bytes!(pie); = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: expected a byte literal - --> $DIR/concat-bytes-error.rs:5:19 + --> $DIR/concat-bytes-error.rs:9:19 | LL | concat_bytes!(pie, pie); | ^^^ ^^^ @@ -15,85 +15,126 @@ LL | concat_bytes!(pie, pie); = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: cannot concatenate string literals - --> $DIR/concat-bytes-error.rs:6:19 + --> $DIR/concat-bytes-error.rs:12:19 | LL | concat_bytes!("tnrsi", "tnri"); | ^^^^^^^ help: try using a byte string: `b"tnrsi"` +error: cannot concatenate string literals + --> $DIR/concat-bytes-error.rs:14:19 + | +LL | concat_bytes!(r"tnrsi", r"tnri"); + | ^^^^^^^^ help: try using a byte string: `br"tnrsi"` + +error: cannot concatenate string literals + --> $DIR/concat-bytes-error.rs:16:19 + | +LL | concat_bytes!(r#"tnrsi"#, r###"tnri"###); + | ^^^^^^^^^^ help: try using a byte string: `br#"tnrsi"#` + +error: cannot concatenate C string literals + --> $DIR/concat-bytes-error.rs:18:19 + | +LL | concat_bytes!(c"tnrsi", c"tnri"); + | ^^^^^^^^ help: try using a null-terminated byte string: `b"tnrsi\0"` + | +note: concatenating C strings is ambiguous about including the '\0' + --> $DIR/concat-bytes-error.rs:18:19 + | +LL | concat_bytes!(c"tnrsi", c"tnri"); + | ^^^^^^^^ + = note: concatenating C strings is ambiguous about including the '\0' + +error: cannot concatenate C string literals + --> $DIR/concat-bytes-error.rs:20:19 + | +LL | concat_bytes!(cr"tnrsi", cr"tnri"); + | ^^^^^^^^^ + | + = note: concatenating C strings is ambiguous about including the '\0' + +error: cannot concatenate C string literals + --> $DIR/concat-bytes-error.rs:21:19 + | +LL | concat_bytes!(cr#"tnrsi"#, cr###"tnri"###); + | ^^^^^^^^^^^ + | + = note: concatenating C strings is ambiguous about including the '\0' + error: cannot concatenate float literals - --> $DIR/concat-bytes-error.rs:7:19 + --> $DIR/concat-bytes-error.rs:24:19 | LL | concat_bytes!(2.8); | ^^^ error: cannot concatenate numeric literals - --> $DIR/concat-bytes-error.rs:8:19 + --> $DIR/concat-bytes-error.rs:25:19 | LL | concat_bytes!(300); | ^^^ help: try wrapping the number in an array: `[300]` error: cannot concatenate character literals - --> $DIR/concat-bytes-error.rs:9:19 + --> $DIR/concat-bytes-error.rs:27:19 | LL | concat_bytes!('a'); | ^^^ help: try using a byte character: `b'a'` error: cannot concatenate boolean literals - --> $DIR/concat-bytes-error.rs:10:19 + --> $DIR/concat-bytes-error.rs:29:19 | LL | concat_bytes!(true, false); | ^^^^ error: cannot concatenate numeric literals - --> $DIR/concat-bytes-error.rs:11:19 + --> $DIR/concat-bytes-error.rs:30:19 | LL | concat_bytes!(42, b"va", b'l'); | ^^ help: try wrapping the number in an array: `[42]` error: cannot concatenate numeric literals - --> $DIR/concat-bytes-error.rs:12:19 + --> $DIR/concat-bytes-error.rs:32:19 | LL | concat_bytes!(42, b"va", b'l', [1, 2]); | ^^ help: try wrapping the number in an array: `[42]` error: cannot concatenate string literals - --> $DIR/concat-bytes-error.rs:14:9 + --> $DIR/concat-bytes-error.rs:37:9 | LL | "hi", | ^^^^ error: cannot concatenate character literals - --> $DIR/concat-bytes-error.rs:17:9 + --> $DIR/concat-bytes-error.rs:40:9 | LL | 'a', | ^^^ help: try using a byte character: `b'a'` error: cannot concatenate boolean literals - --> $DIR/concat-bytes-error.rs:20:9 + --> $DIR/concat-bytes-error.rs:44:9 | LL | true, | ^^^^ error: cannot concatenate boolean literals - --> $DIR/concat-bytes-error.rs:23:9 + --> $DIR/concat-bytes-error.rs:47:9 | LL | false, | ^^^^^ error: cannot concatenate float literals - --> $DIR/concat-bytes-error.rs:26:9 + --> $DIR/concat-bytes-error.rs:50:9 | LL | 2.6, | ^^^ error: numeric literal is out of bounds - --> $DIR/concat-bytes-error.rs:29:9 + --> $DIR/concat-bytes-error.rs:53:9 | LL | 265, | ^^^ error: expected a byte literal - --> $DIR/concat-bytes-error.rs:32:9 + --> $DIR/concat-bytes-error.rs:56:9 | LL | -33, | ^^^ @@ -101,7 +142,7 @@ LL | -33, = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: cannot concatenate doubly nested array - --> $DIR/concat-bytes-error.rs:35:9 + --> $DIR/concat-bytes-error.rs:59:9 | LL | b"hi!", | ^^^^^^ @@ -110,43 +151,43 @@ LL | b"hi!", = help: try flattening the array error: cannot concatenate doubly nested array - --> $DIR/concat-bytes-error.rs:38:9 + --> $DIR/concat-bytes-error.rs:62:9 | LL | [5, 6, 7], | ^^^^^^^^^ error: cannot concatenate numeric literals - --> $DIR/concat-bytes-error.rs:40:19 + --> $DIR/concat-bytes-error.rs:64:19 | LL | concat_bytes!(5u16); | ^^^^ help: try wrapping the number in an array: `[5u16]` error: numeric literal is not a `u8` - --> $DIR/concat-bytes-error.rs:41:20 + --> $DIR/concat-bytes-error.rs:66:20 | LL | concat_bytes!([5u16]); | ^^^^ error: repeat count is not a positive number - --> $DIR/concat-bytes-error.rs:42:23 + --> $DIR/concat-bytes-error.rs:67:23 | LL | concat_bytes!([3; ()]); | ^^ error: repeat count is not a positive number - --> $DIR/concat-bytes-error.rs:43:23 + --> $DIR/concat-bytes-error.rs:68:23 | LL | concat_bytes!([3; -2]); | ^^ error: repeat count is not a positive number - --> $DIR/concat-bytes-error.rs:44:25 + --> $DIR/concat-bytes-error.rs:69:25 | LL | concat_bytes!([pie; -2]); | ^^ error: expected a byte literal - --> $DIR/concat-bytes-error.rs:45:20 + --> $DIR/concat-bytes-error.rs:70:20 | LL | concat_bytes!([pie; 2]); | ^^^ @@ -154,28 +195,28 @@ LL | concat_bytes!([pie; 2]); = note: only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()` error: cannot concatenate float literals - --> $DIR/concat-bytes-error.rs:46:20 + --> $DIR/concat-bytes-error.rs:71:20 | LL | concat_bytes!([2.2; 0]); | ^^^ error: repeat count is not a positive number - --> $DIR/concat-bytes-error.rs:47:25 + --> $DIR/concat-bytes-error.rs:72:25 | LL | concat_bytes!([5.5; ()]); | ^^ error: cannot concatenate doubly nested array - --> $DIR/concat-bytes-error.rs:48:20 + --> $DIR/concat-bytes-error.rs:73:20 | LL | concat_bytes!([[1, 2, 3]; 3]); | ^^^^^^^^^ error: cannot concatenate doubly nested array - --> $DIR/concat-bytes-error.rs:49:20 + --> $DIR/concat-bytes-error.rs:74:20 | LL | concat_bytes!([[42; 2]; 3]); | ^^^^^^^ -error: aborting due to 28 previous errors +error: aborting due to 33 previous errors