diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 26f155adcc..5a969680d6 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -362,6 +362,7 @@ pub enum Edition { impl Edition { pub const CURRENT: Edition = Edition::Edition2021; + pub const DEFAULT: Edition = Edition::Edition2015; } #[derive(Default, Debug, Clone, PartialEq, Eq)] diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs index 901c446465..91b99abc1a 100644 --- a/crates/hir-def/src/db.rs +++ b/crates/hir-def/src/db.rs @@ -24,9 +24,10 @@ use crate::{ AttrDefId, BlockId, BlockLoc, ConstBlockId, ConstBlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, InTypeConstId, InTypeConstLoc, LocalEnumVariantId, - LocalFieldId, Macro2Id, Macro2Loc, MacroId, MacroRulesId, MacroRulesLoc, ProcMacroId, - ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, - TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId, + LocalFieldId, Macro2Id, Macro2Loc, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, + ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitAliasId, + TraitAliasLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, + VariantId, }; #[salsa::query_group(InternDatabaseStorage)] @@ -338,8 +339,10 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { span: db .span_map(loc.id.file_id()) .span_for_range(db.ast_id_map(loc.id.file_id()).get(makro.ast_id).text_range()), + edition: loc.edition, } } + MacroId::MacroRulesId(it) => { let loc: MacroRulesLoc = it.lookup(db); @@ -348,11 +351,14 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { MacroDefId { krate: loc.container.krate, kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()), - local_inner: loc.local_inner, - allow_internal_unsafe: loc.allow_internal_unsafe, + local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER), + allow_internal_unsafe: loc + .flags + .contains(MacroRulesLocFlags::ALLOW_INTERNAL_UNSAFE), span: db .span_map(loc.id.file_id()) .span_for_range(db.ast_id_map(loc.id.file_id()).get(makro.ast_id).text_range()), + edition: loc.edition, } } MacroId::ProcMacroId(it) => { @@ -372,6 +378,7 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { span: db .span_map(loc.id.file_id()) .span_for_range(db.ast_id_map(loc.id.file_id()).get(makro.ast_id).text_range()), + edition: loc.edition, } } } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 37f96df269..22ba3aab4e 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -63,7 +63,7 @@ use std::{ panic::{RefUnwindSafe, UnwindSafe}, }; -use base_db::{impl_intern_key, salsa, CrateId}; +use base_db::{impl_intern_key, salsa, CrateId, Edition}; use hir_expand::{ ast_id_map::{AstIdNode, FileAstId}, attrs::{Attr, AttrId, AttrInput}, @@ -369,6 +369,7 @@ pub struct Macro2Loc { pub id: ItemTreeId, pub expander: MacroExpander, pub allow_internal_unsafe: bool, + pub edition: Edition, } impl_intern!(Macro2Id, Macro2Loc, intern_macro2, lookup_intern_macro2); @@ -379,11 +380,19 @@ pub struct MacroRulesLoc { pub container: ModuleId, pub id: ItemTreeId, pub expander: MacroExpander, - pub allow_internal_unsafe: bool, - pub local_inner: bool, + pub flags: MacroRulesLocFlags, + pub edition: Edition, } impl_intern!(MacroRulesId, MacroRulesLoc, intern_macro_rules, lookup_intern_macro_rules); +bitflags::bitflags! { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub struct MacroRulesLocFlags: u8 { + const ALLOW_INTERNAL_UNSAFE = 1 << 0; + const LOCAL_INNER = 1 << 1; + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct ProcMacroId(salsa::InternId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -392,6 +401,7 @@ pub struct ProcMacroLoc { pub id: ItemTreeId, pub expander: CustomProcMacroExpander, pub kind: ProcMacroKind, + pub edition: Edition, } impl_intern!(ProcMacroId, ProcMacroLoc, intern_proc_macro, lookup_intern_proc_macro); diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 514219ee71..d4798f4507 100644 --- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -163,31 +163,43 @@ fn main() { ""; } fn test_assert_expand() { check( r#" -#[rustc_builtin_macro] -macro_rules! assert { - ($cond:expr) => ({ /* compiler built-in */ }); - ($cond:expr, $($args:tt)*) => ({ /* compiler built-in */ }) -} - +//- minicore: assert fn main() { assert!(true, "{} {:?}", arg1(a, b, c), arg2); } "#, - expect![[r##" -#[rustc_builtin_macro] -macro_rules! assert { - ($cond:expr) => ({ /* compiler built-in */ }); - ($cond:expr, $($args:tt)*) => ({ /* compiler built-in */ }) -} - + expect![[r#" fn main() { { if !(true ) { - $crate::panic!("{} {:?}", arg1(a, b, c), arg2); + $crate::panic::panic_2021!("{} {:?}", arg1(a, b, c), arg2); } }; } -"##]], +"#]], + ); +} + +// FIXME: This is the wrong expansion, see FIXME on `builtin_fn_macro::use_panic_2021` +#[test] +fn test_assert_expand_2015() { + check( + r#" +//- minicore: assert +//- /main.rs edition:2015 +fn main() { + assert!(true, "{} {:?}", arg1(a, b, c), arg2); +} +"#, + expect![[r#" +fn main() { + { + if !(true ) { + $crate::panic::panic_2021!("{} {:?}", arg1(a, b, c), arg2); + } + }; +} +"#]], ); } diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs index 095534058c..c3381af44c 100644 --- a/crates/hir-def/src/nameres/collector.rs +++ b/crates/hir-def/src/nameres/collector.rs @@ -54,8 +54,9 @@ use crate::{ AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, EnumVariantId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId, - MacroRulesId, MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, - StructLoc, TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId, UseLoc, + MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId, + ProcMacroLoc, StaticLoc, StructLoc, TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc, + UnresolvedMacro, UseId, UseLoc, }; static GLOB_RECURSION_LIMIT: Limit = Limit::new(100); @@ -612,9 +613,14 @@ impl DefCollector<'_> { _ => (CustomProcMacroExpander::dummy(), kind), }; - let proc_macro_id = - ProcMacroLoc { container: self.def_map.crate_root(), id, expander, kind } - .intern(self.db); + let proc_macro_id = ProcMacroLoc { + container: self.def_map.crate_root(), + id, + expander, + kind, + edition: self.def_map.data.edition, + } + .intern(self.db); self.define_proc_macro(def.name.clone(), proc_macro_id); let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap(); if let ProcMacroKind::CustomDerive { helpers } = def.kind { @@ -2136,12 +2142,16 @@ impl ModCollector<'_, '_> { }; let allow_internal_unsafe = attrs.by_key("allow_internal_unsafe").exists(); + let mut flags = MacroRulesLocFlags::empty(); + flags.set(MacroRulesLocFlags::LOCAL_INNER, local_inner); + flags.set(MacroRulesLocFlags::ALLOW_INTERNAL_UNSAFE, allow_internal_unsafe); + let macro_id = MacroRulesLoc { container: module, id: ItemTreeId::new(self.tree_id, id), - local_inner, - allow_internal_unsafe, + flags, expander, + edition: self.def_collector.def_map.data.edition, } .intern(self.def_collector.db); self.def_collector.define_macro_rules( @@ -2207,6 +2217,7 @@ impl ModCollector<'_, '_> { id: ItemTreeId::new(self.tree_id, id), expander, allow_internal_unsafe, + edition: self.def_collector.def_map.data.edition, } .intern(self.def_collector.db); self.def_collector.define_macro_def( diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs index 2d7531d56d..0475a0f4ac 100644 --- a/crates/hir-expand/src/builtin_fn_macro.rs +++ b/crates/hir-expand/src/builtin_fn_macro.rs @@ -13,10 +13,11 @@ use syntax::{ use crate::{ db::ExpandDatabase, - hygiene::span_with_def_site_ctxt, - name, quote, + hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt}, + name::{self, known}, + quote, tt::{self, DelimSpan}, - ExpandError, ExpandResult, HirFileIdExt, MacroCallId, MacroCallLoc, + ExpandError, ExpandResult, HirFileIdExt, MacroCallId, }; macro_rules! register_builtin { @@ -196,32 +197,38 @@ fn stringify_expand( } fn assert_expand( - _db: &dyn ExpandDatabase, - _id: MacroCallId, + db: &dyn ExpandDatabase, + id: MacroCallId, tt: &tt::Subtree, span: Span, ) -> ExpandResult { - let args = parse_exprs_with_sep(tt, ',', span); + let call_site_span = span_with_call_site_ctxt(db, span, id); + let args = parse_exprs_with_sep(tt, ',', call_site_span); let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span }; let expanded = match &*args { [cond, panic_args @ ..] => { let comma = tt::Subtree { - delimiter: tt::Delimiter::invisible_spanned(span), + delimiter: tt::Delimiter::invisible_spanned(call_site_span), token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', spacing: tt::Spacing::Alone, - span, + span: call_site_span, }))], }; let cond = cond.clone(); let panic_args = itertools::Itertools::intersperse(panic_args.iter().cloned(), comma); - quote! {span =>{ + let mac = if use_panic_2021(db, span) { + quote! {call_site_span => #dollar_crate::panic::panic_2021!(##panic_args) } + } else { + quote! {call_site_span => #dollar_crate::panic!(##panic_args) } + }; + quote! {call_site_span =>{ if !(#cond) { - #dollar_crate::panic!(##panic_args); + #mac; } }} } - [] => quote! {span =>{}}, + [] => quote! {call_site_span =>{}}, }; ExpandResult::ok(expanded) @@ -337,17 +344,23 @@ fn panic_expand( tt: &tt::Subtree, span: Span, ) -> ExpandResult { - let loc: MacroCallLoc = db.lookup_intern_macro_call(id); let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span }; + let call_site_span = span_with_call_site_ctxt(db, span, id); + + let mac = + if use_panic_2021(db, call_site_span) { known::panic_2021 } else { known::panic_2015 }; + // Expand to a macro call `$crate::panic::panic_{edition}` - let mut call = if db.crate_graph()[loc.krate].edition >= Edition::Edition2021 { - quote!(span =>#dollar_crate::panic::panic_2021!) - } else { - quote!(span =>#dollar_crate::panic::panic_2015!) - }; + let mut call = quote!(call_site_span =>#dollar_crate::panic::#mac!); // Pass the original arguments - call.token_trees.push(tt::TokenTree::Subtree(tt.clone())); + let mut subtree = tt.clone(); + subtree.delimiter = tt::Delimiter { + open: call_site_span, + close: call_site_span, + kind: tt::DelimiterKind::Parenthesis, + }; + call.token_trees.push(tt::TokenTree::Subtree(subtree)); ExpandResult::ok(call) } @@ -357,20 +370,50 @@ fn unreachable_expand( tt: &tt::Subtree, span: Span, ) -> ExpandResult { - let loc: MacroCallLoc = db.lookup_intern_macro_call(id); - // Expand to a macro call `$crate::panic::unreachable_{edition}` let dollar_crate = tt::Ident { text: SmolStr::new_inline("$crate"), span }; - let mut call = if db.crate_graph()[loc.krate].edition >= Edition::Edition2021 { - quote!(span =>#dollar_crate::panic::unreachable_2021!) + let call_site_span = span_with_call_site_ctxt(db, span, id); + + let mac = if use_panic_2021(db, call_site_span) { + known::unreachable_2021 } else { - quote!(span =>#dollar_crate::panic::unreachable_2015!) + known::unreachable_2015 }; + // Expand to a macro call `$crate::panic::panic_{edition}` + let mut call = quote!(call_site_span =>#dollar_crate::panic::#mac!); + // Pass the original arguments - call.token_trees.push(tt::TokenTree::Subtree(tt.clone())); + let mut subtree = tt.clone(); + subtree.delimiter = tt::Delimiter { + open: call_site_span, + close: call_site_span, + kind: tt::DelimiterKind::Parenthesis, + }; + call.token_trees.push(tt::TokenTree::Subtree(subtree)); ExpandResult::ok(call) } +fn use_panic_2021(db: &dyn ExpandDatabase, span: Span) -> bool { + // To determine the edition, we check the first span up the expansion + // stack that does not have #[allow_internal_unstable(edition_panic)]. + // (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.) + loop { + let Some(expn) = db.lookup_intern_syntax_context(span.ctx).outer_expn else { + break false; + }; + let expn = db.lookup_intern_macro_call(expn); + // FIXME: Record allow_internal_unstable in the macro def (not been done yet because it + // would consume quite a bit extra memory for all call locs...) + // if let Some(features) = expn.def.allow_internal_unstable { + // if features.iter().any(|&f| f == sym::edition_panic) { + // span = expn.call_site; + // continue; + // } + // } + break expn.def.edition >= Edition::Edition2021; + } +} + fn unquote_str(lit: &tt::Literal) -> Option { let lit = ast::make::tokens::literal(&lit.to_string()); let token = ast::String::cast(lit)?; diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs index 3df62aefaa..b5197d4c25 100644 --- a/crates/hir-expand/src/lib.rs +++ b/crates/hir-expand/src/lib.rs @@ -28,7 +28,7 @@ use triomphe::Arc; use std::{fmt, hash::Hash}; -use base_db::{CrateId, FileId}; +use base_db::{CrateId, Edition, FileId}; use either::Either; use span::{FileRange, HirFileIdRepr, Span, SyntaxContextId}; use syntax::{ @@ -176,6 +176,7 @@ pub struct MacroCallLoc { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MacroDefId { pub krate: CrateId, + pub edition: Edition, pub kind: MacroDefKind, pub local_inner: bool, pub allow_internal_unsafe: bool, diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs index a321f94cd7..d122938e8e 100644 --- a/crates/hir-expand/src/name.rs +++ b/crates/hir-expand/src/name.rs @@ -318,6 +318,10 @@ pub mod known { new_lower_hex, new_upper_hex, from_usize, + panic_2015, + panic_2021, + unreachable_2015, + unreachable_2021, // Components of known path (type name) Iterator, IntoIterator, diff --git a/crates/hir-expand/src/quote.rs b/crates/hir-expand/src/quote.rs index 7c24724690..9bdd75f9d2 100644 --- a/crates/hir-expand/src/quote.rs +++ b/crates/hir-expand/src/quote.rs @@ -2,6 +2,8 @@ use span::Span; +use crate::name::Name; + // A helper macro quote macro // FIXME: // 1. Not all puncts are handled @@ -180,7 +182,7 @@ impl ToTokenTree for crate::tt::Subtree { } macro_rules! impl_to_to_tokentrees { - ($($span:ident: $ty:ty => $this:ident $im:block);*) => { + ($($span:ident: $ty:ty => $this:ident $im:block;)*) => { $( impl ToTokenTree for $ty { fn to_token($this, $span: Span) -> crate::tt::TokenTree { @@ -209,7 +211,8 @@ impl_to_to_tokentrees! { _span: crate::tt::Ident => self { self }; _span: crate::tt::Punct => self { self }; span: &str => self { crate::tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), span}}; - span: String => self { crate::tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), span}} + span: String => self { crate::tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), span}}; + span: Name => self { crate::tt::Ident{text: self.to_smol_str(), span}}; } #[cfg(test)] diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index f766747d70..1f3136404c 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -1381,6 +1381,7 @@ mod macros { // region:assert #[macro_export] #[rustc_builtin_macro] + #[allow_internal_unstable(core_panic, edition_panic, generic_assert_internals)] macro_rules! assert { ($($arg:tt)*) => { /* compiler built-in */ @@ -1389,6 +1390,7 @@ mod macros { // endregion:assert // region:fmt + #[allow_internal_unstable(fmt_internals, const_fmt_arguments_new)] #[macro_export] #[rustc_builtin_macro] macro_rules! const_format_args { @@ -1396,6 +1398,7 @@ mod macros { ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }}; } + #[allow_internal_unstable(fmt_internals)] #[macro_export] #[rustc_builtin_macro] macro_rules! format_args { @@ -1403,6 +1406,7 @@ mod macros { ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }}; } + #[allow_internal_unstable(fmt_internals)] #[macro_export] #[rustc_builtin_macro] macro_rules! format_args_nl {