diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index c1b3aff4e69f6..b2de8fbfe33b6 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -17,9 +17,9 @@ use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib use crate::macros::{MacroRulesScope, sub_namespace_match}; use crate::{ AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, CmResolver, Determinacy, - Finalize, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, - NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, - Resolver, Scope, ScopeSet, Segment, Used, Weak, errors, + Finalize, ImportKind, LexicalScopeBinding, LookaheadItemInBlock, Module, ModuleKind, + ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res, + ResolutionError, Resolver, Scope, ScopeSet, Segment, Used, Weak, errors, }; #[derive(Copy, Clone)] @@ -333,20 +333,73 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { *original_rib_ident_def, ribs, ))); - } else if let RibKind::Block(Some(module)) = rib.kind - && let Ok(binding) = self.cm().resolve_ident_in_module_unadjusted( - ModuleOrUniformRoot::Module(module), - ident, - ns, - parent_scope, - Shadowing::Unrestricted, - finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }), - ignore_binding, - None, - ) - { - // The ident resolves to an item in a block. - return Some(LexicalScopeBinding::Item(binding)); + } else if let RibKind::Block { module, id: block_id } = rib.kind { + if let Some(items) = self.lookahead_items_in_block.get(&block_id) { + let mut expansion = None; + for (node_id, item) in items + .iter() + .rev() + .filter(|(_, item)| matches!(item, LookaheadItemInBlock::MacroDef { .. })) + { + let LookaheadItemInBlock::MacroDef { def_id, bindings, .. } = item else { + unreachable!(); + }; + if *def_id != self.macro_def(ident.span.ctxt()) { + continue; + } + expansion.get_or_insert(node_id); + ident.span.remove_mark(); + if let Some((original_rib_ident_def, res)) = bindings.get_key_value(&ident) + { + // The ident resolves to a type parameter or local variable. + return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs( + i, + ident, + *res, + finalize.map(|finalize| finalize.path_span), + *original_rib_ident_def, + ribs, + ))); + } + } + if let Some(expansion) = expansion + && items.iter().take_while(|(item_id, _)| !expansion.eq(item_id)).any( + |(_, item)| { + if let LookaheadItemInBlock::Binding { name } = item { + name.name == ident.name + } else { + false + } + }, + ) + { + // return `None` for this case: + // + // ``` + // let a = m!(); + // let b = 1; + // macro_rules! m { () => { b } } + // use b; + // ``` + return None; + } + } + + if let Some(module) = module + && let Ok(binding) = self.cm().resolve_ident_in_module_unadjusted( + ModuleOrUniformRoot::Module(module), + ident, + ns, + parent_scope, + Shadowing::Unrestricted, + finalize.map(|finalize| Finalize { used: Used::Scope, ..finalize }), + ignore_binding, + None, + ) + { + // The ident resolves to an item in a block. + return Some(LexicalScopeBinding::Item(binding)); + } } else if let RibKind::Module(module) = rib.kind { // Encountered a module item, abandon ribs and look into that module and preludes. return self @@ -1166,7 +1219,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for rib in ribs { match rib.kind { RibKind::Normal - | RibKind::Block(..) + | RibKind::Block { .. } | RibKind::FnOrCoroutine | RibKind::Module(..) | RibKind::MacroDefinition(..) @@ -1259,7 +1312,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for rib in ribs { let (has_generic_params, def_kind) = match rib.kind { RibKind::Normal - | RibKind::Block(..) + | RibKind::Block { .. } | RibKind::FnOrCoroutine | RibKind::Module(..) | RibKind::MacroDefinition(..) @@ -1353,7 +1406,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for rib in ribs { let (has_generic_params, def_kind) = match rib.kind { RibKind::Normal - | RibKind::Block(..) + | RibKind::Block { .. } | RibKind::FnOrCoroutine | RibKind::Module(..) | RibKind::MacroDefinition(..) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 5200f9340e115..b53e4eabc40cc 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -39,9 +39,9 @@ use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; use crate::{ - BindingError, BindingKey, Finalize, LexicalScopeBinding, Module, ModuleOrUniformRoot, - NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, TyCtxt, UseError, - Used, errors, path_names_to_string, rustdoc, + BindingError, BindingKey, Finalize, LexicalScopeBinding, LookaheadItemInBlock, Module, + ModuleOrUniformRoot, NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, + TyCtxt, UseError, Used, errors, path_names_to_string, rustdoc, }; mod diagnostics; @@ -102,7 +102,7 @@ impl IntoDiagArg for PatternSource { /// Denotes whether the context for the set of already bound bindings is a `Product` /// or `Or` context. This is used in e.g., `fresh_binding` and `resolve_pattern_inner`. /// See those functions for more information. -#[derive(PartialEq)] +#[derive(PartialEq, Debug)] enum PatBoundCtx { /// A product pattern context, e.g., `Variant(a, b)`. Product, @@ -197,7 +197,29 @@ pub(crate) enum RibKind<'ra> { /// `Block(None)` must be always processed in the same way as `Block(Some(module))` /// with empty `module`. The module can be `None` only because creation of some definitely /// empty modules is skipped as an optimization. - Block(Option>), + Block { + module: Option>, + /// The node id of block kind, which stores all bindings defined in + /// this local scope, for these features: + /// + /// - Forward reference detection: + /// + /// ```ignore (illustrative) + /// let a = b; // displays '`b` is defined at ' instead of ''b' not found' + /// let b = 42; + /// ``` + /// + /// - Correctly resolves the hoisting bindings within macro expand: + /// + /// ```ignore (illustrative) + /// fn f() {} + /// let a: i16 = m!(); // throw error because it should use the local `f` rather than `fn f` + /// let f = || -> i16 { 42 }; + /// macro_rules! m {() => ( f() )} + /// use m; + /// ``` + id: NodeId, + }, /// We passed through an impl or trait and are now in one of its /// methods or associated types. Allow references to ty params that impl or trait @@ -249,7 +271,7 @@ impl RibKind<'_> { pub(crate) fn contains_params(&self) -> bool { match self { RibKind::Normal - | RibKind::Block(..) + | RibKind::Block { .. } | RibKind::FnOrCoroutine | RibKind::ConstantItem(..) | RibKind::Module(_) @@ -2816,7 +2838,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { for parent_rib in self.ribs[ns].iter().rev() { // Break at module or block level, to account for nested items which are // allowed to shadow generic param names. - if matches!(parent_rib.kind, RibKind::Module(..) | RibKind::Block(..)) { + if matches!(parent_rib.kind, RibKind::Module(..) | RibKind::Block { .. }) { break; } @@ -3769,6 +3791,52 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { fn resolve_pattern_top(&mut self, pat: &'ast Pat, pat_src: PatternSource) { let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; self.resolve_pattern(pat, pat_src, &mut bindings); + + let mut last_pat_id = None; + pat.walk(&mut |pat| { + if let PatKind::Ident(..) = pat.kind { + last_pat_id = Some(pat.id); + } + true + }); + + if let Some(last_pat_id) = last_pat_id + && let RibKind::Block { id: block, .. } = self.ribs[ValueNS].last_mut().unwrap().kind + && let Some(items) = self.r.lookahead_items_in_block.get_mut(&block) + { + let start = items.get_index_of(&last_pat_id).unwrap_or_else(|| { + panic!("pattern({pat:#?}) not found in lookahead items"); + }); + // let mut first_macro: Option = None; + // `need_removed` used for avoid injecting masked names into macro definition bindings: + // + // ``` + // let x = 0; + // macro_rules! m0 {() => { x; }} // Injects `let x = 0` into `m0` + // let x = 1; + // macro_rules! m1 {() => { x; }} // Should NOT inject `let x = 0` into `m1` + // ``` + let mut need_removed = FxHashSet::default(); + for (_, item) in items.iter_mut().skip(start + 1) { + match item { + LookaheadItemInBlock::Binding { name } => { + need_removed.insert(name.normalize_to_macro_rules()); + } + LookaheadItemInBlock::MacroDef { bindings: macro_bindings, .. } => { + let bindings = + bindings.last().unwrap().1.iter().filter_map(|(name, res)| { + if !need_removed.contains(&name) { + Some((*name, *res)) + } else { + None + } + }); + macro_bindings.extend(bindings); + } + } + } + } + self.apply_pattern_bindings(bindings); } @@ -4650,11 +4718,12 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let mut num_macro_definition_ribs = 0; if let Some(anonymous_module) = anonymous_module { debug!("(resolving block) found anonymous module, moving down"); - self.ribs[ValueNS].push(Rib::new(RibKind::Block(Some(anonymous_module)))); - self.ribs[TypeNS].push(Rib::new(RibKind::Block(Some(anonymous_module)))); + let rib_kind = RibKind::Block { module: Some(anonymous_module), id: block.id }; + self.ribs[ValueNS].push(Rib::new(rib_kind)); + self.ribs[TypeNS].push(Rib::new(rib_kind)); self.parent_scope.module = anonymous_module; } else { - self.ribs[ValueNS].push(Rib::new(RibKind::Block(None))); + self.ribs[ValueNS].push(Rib::new(RibKind::Block { module: None, id: block.id })); } // Descend into the block. @@ -4664,7 +4733,6 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { { num_macro_definition_ribs += 1; let res = self.r.local_def_id(item.id).to_def_id(); - self.ribs[ValueNS].push(Rib::new(RibKind::MacroDefinition(res))); self.label_ribs.push(Rib::new(RibKind::MacroDefinition(res))); } @@ -4674,7 +4742,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // Move back up. self.parent_scope.module = orig_module; for _ in 0..num_macro_definition_ribs { - self.ribs[ValueNS].pop(); + // pop `MacroDefinition` self.label_ribs.pop(); } self.last_block_rib = self.ribs[ValueNS].pop(); @@ -5134,6 +5202,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { /// lifetime generic parameters and function parameters. struct ItemInfoCollector<'a, 'ra, 'tcx> { r: &'a mut Resolver<'ra, 'tcx>, + current_block: Option, } impl ItemInfoCollector<'_, '_, '_> { @@ -5189,12 +5258,20 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { } } } - + ItemKind::MacroDef(_, _) => { + if let Some(block_id) = self.current_block { + let def_id = self.r.local_def_id(item.id).to_def_id(); + let items = self.r.lookahead_items_in_block.entry(block_id).or_default(); + items.insert( + item.id, + LookaheadItemInBlock::MacroDef { bindings: Default::default(), def_id }, + ); + } + } ItemKind::Mod(..) | ItemKind::Static(..) | ItemKind::Use(..) | ItemKind::ExternCrate(..) - | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(..) | ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => {} @@ -5214,11 +5291,30 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { } visit::walk_assoc_item(self, item, ctxt); } + + fn visit_local(&mut self, node: &'ast Local) -> Self::Result { + // collect local bindings into block + node.pat.walk(&mut |pat| { + if let PatKind::Ident(_, name, _) = &pat.kind { + let block_id = self.current_block.unwrap(); + let items = self.r.lookahead_items_in_block.entry(block_id).or_default(); + items.insert(pat.id, LookaheadItemInBlock::Binding { name: *name }); + } + true + }); + visit::walk_local(self, node) + } + + fn visit_block(&mut self, node: &'ast Block) -> Self::Result { + let saved_block_id = self.current_block.replace(node.id); + visit::walk_block(self, node); + self.current_block = saved_block_id; + } } impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn late_resolve_crate(&mut self, krate: &Crate) { - visit::walk_crate(&mut ItemInfoCollector { r: self }, krate); + visit::walk_crate(&mut ItemInfoCollector { r: self, current_block: None }, krate); let mut late_resolution_visitor = LateResolutionVisitor::new(self); late_resolution_visitor.resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID)); visit::walk_crate(&mut late_resolution_visitor, krate); diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 9b201e40d1393..ee41d9819218f 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -898,7 +898,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if path.len() == 1 { for rib in self.ribs[ns].iter().rev() { let item = path[0].ident; - if let RibKind::Module(module) | RibKind::Block(Some(module)) = rib.kind + if let RibKind::Module(module) | RibKind::Block { module: Some(module), .. } = + rib.kind && let Some(did) = find_doc_alias_name(self.r, module, item.name) { return Some((did, item)); @@ -2438,7 +2439,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { ) -> TypoCandidate { let mut names = Vec::new(); if let [segment] = path { - let mut ctxt = segment.ident.span.ctxt(); + let ctxt = segment.ident.span.ctxt(); // Search in lexical scope. // Walk backwards up the ribs in scope and collect candidates. @@ -2456,7 +2457,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } - if let RibKind::Block(Some(module)) = rib.kind { + if let RibKind::Block { module: Some(module), .. } = rib.kind { self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt)); } else if let RibKind::Module(module) = rib.kind { // Encountered a module item, abandon ribs and look into that module and preludes. @@ -2469,14 +2470,6 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { ); break; } - - if let RibKind::MacroDefinition(def) = rib.kind - && def == self.r.macro_def(ctxt) - { - // If an invocation of this macro created `ident`, give up on `ident` - // and switch to `ident`'s source from the macro definition. - ctxt.remove_mark(); - } } } else { // Search in module. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ca9c124fca63c..aaf95f67546b7 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1062,6 +1062,14 @@ pub struct ResolverOutputs { pub ast_lowering: ResolverAstLowering, } +#[derive(Debug)] +enum LookaheadItemInBlock { + /// such as `let x = 1;` + Binding { name: Ident }, + /// such as `macro_rules! foo { ... }` + MacroDef { def_id: DefId, bindings: FxIndexMap }, +} + /// The main resolver class. /// /// This is the visitor that walks the whole crate. @@ -1130,6 +1138,7 @@ pub struct Resolver<'ra, 'tcx> { /// There will be an anonymous module created around `g` with the ID of the /// entry block for `f`. block_map: NodeMap>, + lookahead_items_in_block: NodeMap>, /// A fake module that contains no definition and no prelude. Used so that /// some AST passes can generate identifiers that only resolve to local or /// lang items. @@ -1653,6 +1662,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { current_crate_outer_attr_insert_span, mods_with_parse_errors: Default::default(), impl_trait_names: Default::default(), + lookahead_items_in_block: Default::default(), .. }; diff --git a/tests/ui/resolve/binding-should-not-shadow-def-in-macro-expand.rs b/tests/ui/resolve/binding-should-not-shadow-def-in-macro-expand.rs new file mode 100644 index 0000000000000..71ae1592158e6 --- /dev/null +++ b/tests/ui/resolve/binding-should-not-shadow-def-in-macro-expand.rs @@ -0,0 +1,144 @@ +//@ edition:2018 + +type FnF = i8; +type BindingF = i16; + +fn main() {} + +fn f_without_definition_f(f: impl Fn() -> BindingF) { + // param f -> macro m + let a: BindingF = m!(); + macro_rules! m {() => ( f() )} + use m; +} + +fn fn0(f: impl Fn() -> BindingF) { + // param f -> fn f -> macro m + + let a0: FnF = m!(); + fn f() -> FnF { 42 } + let a1: FnF = m!(); + macro_rules! m {() => ( f() )} + use m; + let a2: FnF = m!(); +} + +fn fn1(f: impl Fn() -> BindingF) { + // param f -> macro m -> fn f + + let a0: FnF = m!(); + macro_rules! m {() => ( f() )} + use m; + let a1: FnF = m!(); + fn f() -> FnF { 42 } + let a2: FnF = m!(); +} + +fn closure() { + let c_without_definition_f = |f: BindingF| { + // param f -> macro m + let a1: BindingF = m!(); + macro_rules! m {() => ( f )} + use m; + }; + + let c0 = |f: BindingF| { + // param f -> fn f -> macro m + let a0: FnF = m!(); + fn f() -> FnF { 42 } + let a1: FnF = m!(); + macro_rules! m {() => ( f() )} + use m; + let a2: FnF = m!(); + }; + + let c1 = |f: BindingF| { + // param f -> macro m -> fn f + let a0: FnF = m!(); + macro_rules! m {() => ( f() )} + use m; + let a1: FnF = m!(); + fn f() -> FnF { 42 } + let a2: FnF = m!(); + }; +} + +fn for_loop() { + // for f -> macro m -> fn f + for f in 0..42 as BindingF { + let a0: FnF = m!(); + macro_rules! m {() => ( f() )} + use m; + let a1: FnF = m!(); + fn f() -> FnF { 42 } + let a2: FnF = m!(); + } + + // for f -> fn f -> macro m + for f in 0..42 as BindingF { + let a0: FnF = m!(); + fn f() -> FnF { 42 } + let a1: FnF = m!(); + macro_rules! m {() => ( f() )} + use m; + let a2: FnF = m!(); + } +} + +fn match_arm() { + // match f -> macro m -> fn f + match 42 as BindingF { + f => { + let a0: FnF = m!(); + macro_rules! m {() => ( f() )} + use m; + let a1: FnF = m!(); + fn f() -> FnF { 42 } + let a2: FnF = m!(); + } + } + + // match f -> fn f -> macro m + match 42 as BindingF { + f => { + let a0: FnF = m!(); + fn f() -> FnF { 42 } + let a1: FnF = m!(); + macro_rules! m {() => ( f() )} + use m; + let a2: FnF = m!(); + } + } +} + +fn let_in_if_expr() { + if let Some(f) = Some(|| -> BindingF { 42 }) { + // expr let f -> fn f -> macro f + let a0: FnF = m!(); + fn f() -> FnF { 42 } + let a1: FnF = m!(); + macro_rules! m {() => { f() };} + use m; + let a2: FnF = m!(); + } + + if let Some(f) = Some(|| -> BindingF { 42 }) { + // expr let f -> macro f -> fn f + let a0: FnF = m!(); + macro_rules! m {() => { f() };} + use m; + let a1: FnF = m!(); + fn f() -> FnF { 42 } + let a2: FnF = m!(); + } +} + +fn cannot_access_cross_fn() { + let f = || -> BindingF { 42 }; + fn g() { + macro_rules! m { + () => { f() }; //~ ERROR can't capture dynamic environment in a fn item + } + m!(); + } +} diff --git a/tests/ui/resolve/binding-should-not-shadow-def-in-macro-expand.stderr b/tests/ui/resolve/binding-should-not-shadow-def-in-macro-expand.stderr new file mode 100644 index 0000000000000..77e8955f89f8f --- /dev/null +++ b/tests/ui/resolve/binding-should-not-shadow-def-in-macro-expand.stderr @@ -0,0 +1,15 @@ +error[E0434]: can't capture dynamic environment in a fn item + --> $DIR/binding-should-not-shadow-def-in-macro-expand.rs:140:21 + | +LL | () => { f() }; + | ^ +LL | } +LL | m!(); + | ---- in this macro invocation + | + = help: use the `|| { ... }` closure form instead + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0434`. diff --git a/tests/ui/resolve/fresh-should-shadow-definitation-in-decl-macro-expand.rs b/tests/ui/resolve/fresh-should-shadow-definitation-in-decl-macro-expand.rs new file mode 100644 index 0000000000000..4f15069ba5d85 --- /dev/null +++ b/tests/ui/resolve/fresh-should-shadow-definitation-in-decl-macro-expand.rs @@ -0,0 +1,99 @@ +//@ edition:2018 +// issue#95237 + +#![feature(decl_macro)] + +type FnF = i8; +type BindingF = i16; + +fn f_without_definition_f() { + let f = || -> BindingF { 42 }; + let a: BindingF = m!(); + macro m() { f() } +} + +fn f_without_closure_f() { + fn f() -> FnF { 42 } + let a: FnF = m!(); + macro m() { f() } +} + +fn f0() { + // let f -> macro m -> fn f + + let a0: BindingF = m!(); //~ NOTE in this expansion of m! + let f = || -> BindingF { 42 }; + let a1: BindingF = m!(); + macro m() { f() } //~ ERROR cannot find function `f` in this scope + //~| NOTE not found in this scope + let a2: BindingF = m!(); + fn f() -> FnF { 42 } //~ NOTE you might have meant to refer to this function + let a3: BindingF = m!(); +} + +fn f1() { + // let f -> fn f -> macro m + + let a0: BindingF = m!(); //~ NOTE in this expansion of m! + let f = || -> BindingF { 42 }; + let a1: BindingF = m!(); + fn f() -> FnF { 42 } //~ NOTE you might have meant to refer to this function + let a2: BindingF = m!(); + macro m() { f() } //~ ERROR cannot find function `f` in this scope + //~| NOTE not found in this scope + let a3: BindingF = m!(); +} + +fn f2() { + // fn f -> let f -> macro m + + let a0: BindingF = m!(); //~ NOTE in this expansion of m! + fn f() -> FnF { 42 } //~ NOTE you might have meant to refer to this function + //~| NOTE you might have meant to refer to this function + let a1: BindingF = m!(); //~ NOTE in this expansion of m! + let f = || -> BindingF { 42 }; + let a2: BindingF = m!(); + macro m() { f() } //~ ERROR cannot find function `f` in this scope + //~| ERROR cannot find function `f` in this scope + //~| NOTE not found in this scope + //~| NOTE not found in this scope + let a3: BindingF = m!(); +} + +fn f3() { + // fn f -> macro m -> let f + + let a0: FnF = m!(); + fn f() -> FnF { 42 } + let a1: FnF = m!(); + macro m() { f() } + let a2: FnF = m!(); + let f = || -> BindingF { 42 }; + let a3: FnF = m!(); +} + +fn f4() { + // macro m -> fn f -> let f; + + let a0: FnF = m!(); + macro m() { f() } + let a1: FnF = m!(); + fn f() -> FnF { 42 } + let a2: FnF = m!(); + let f = || -> BindingF { 42 }; + let a3: FnF = m!(); +} + +fn f5() { + // macro m -> let f -> fn f; + + let a0: FnF = m!(); + macro m() { f() } + let a1: FnF = m!(); + let f = || -> BindingF { 42 }; + let a2: FnF = m!(); + fn f() -> FnF { 42 } + let a3: FnF = m!(); +} + +fn main () {} diff --git a/tests/ui/resolve/fresh-should-shadow-definitation-in-decl-macro-expand.stderr b/tests/ui/resolve/fresh-should-shadow-definitation-in-decl-macro-expand.stderr new file mode 100644 index 0000000000000..aa6f2ea23d2a5 --- /dev/null +++ b/tests/ui/resolve/fresh-should-shadow-definitation-in-decl-macro-expand.stderr @@ -0,0 +1,58 @@ +error[E0425]: cannot find function `f` in this scope + --> $DIR/fresh-should-shadow-definitation-in-decl-macro-expand.rs:27:17 + | +LL | let a0: BindingF = m!(); + | ---- in this macro invocation +... +LL | macro m() { f() } + | ^ not found in this scope +... +LL | fn f() -> FnF { 42 } + | - you might have meant to refer to this function + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find function `f` in this scope + --> $DIR/fresh-should-shadow-definitation-in-decl-macro-expand.rs:42:17 + | +LL | let a0: BindingF = m!(); + | ---- in this macro invocation +... +LL | fn f() -> FnF { 42 } + | - you might have meant to refer to this function +LL | let a2: BindingF = m!(); +LL | macro m() { f() } + | ^ not found in this scope + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find function `f` in this scope + --> $DIR/fresh-should-shadow-definitation-in-decl-macro-expand.rs:56:17 + | +LL | let a0: BindingF = m!(); + | ---- in this macro invocation +LL | fn f() -> FnF { 42 } + | - you might have meant to refer to this function +... +LL | macro m() { f() } + | ^ not found in this scope + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find function `f` in this scope + --> $DIR/fresh-should-shadow-definitation-in-decl-macro-expand.rs:56:17 + | +LL | fn f() -> FnF { 42 } + | - you might have meant to refer to this function +LL | +LL | let a1: BindingF = m!(); + | ---- in this macro invocation +... +LL | macro m() { f() } + | ^ not found in this scope + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/fresh-should-shadow-definitation-in-macro-expand-in-block.rs b/tests/ui/resolve/fresh-should-shadow-definitation-in-macro-expand-in-block.rs new file mode 100644 index 0000000000000..3a91c79abf759 --- /dev/null +++ b/tests/ui/resolve/fresh-should-shadow-definitation-in-macro-expand-in-block.rs @@ -0,0 +1,190 @@ +//@ edition:2018 + +// issue#95237 + +type FnF = i8; +type BindingF = i16; + +fn b_without_definition_f() { + let f = || -> BindingF { 42 }; + { + let a: BindingF = m!(); + } + macro_rules! m {() => ( f() )} + use m; +} + +fn b_without_closure_f() { + fn f() -> FnF { 42 } + { + let a: FnF = m!(); + } + macro_rules! m {() => ( f() )} + use m; +} + +fn ff0() { + // let f -> macro m -> fn f + + { + let a0: BindingF = m!(); //~ NOTE in this expansion of m! + } + let f = || -> BindingF { 42 }; + { + let a1: BindingF = m!(); + } + macro_rules! m {() => ( f() )} //~ ERROR cannot find function `f` in this scope + //~| NOTE not found in this scope + use m; + { + let a2: BindingF = m!(); + } + fn f() -> FnF { 42 } + { + let a3: BindingF = m!(); + } +} + +fn ff1() { + // let f -> fn f -> macro m + + { + let a0: BindingF = m!(); //~ NOTE in this expansion of m! + } + let f = || -> BindingF { 42 }; + { + let a1: BindingF = m!(); + } + fn f() -> FnF { 42 } + { + let a2: BindingF = m!(); + } + macro_rules! m {() => ( f() )} //~ ERROR cannot find function `f` in this scope + //~| NOTE not found in this scope + use m; + { + let a3: BindingF = m!(); + } +} + +fn ff2() { + // fn f -> let f -> macro m + + { + let a0: BindingF = m!(); //~ NOTE in this expansion of m! + } + fn f() -> FnF { 42 } + { + let a1: BindingF = m!(); //~ NOTE in this expansion of m! + } + let f = || -> BindingF { 42 }; + { + let a2: BindingF = m!(); + } + macro_rules! m {() => ( f() )} //~ ERROR cannot find function `f` in this scope + //~| ERROR cannot find function `f` in this scope + //~| NOTE not found in this scope + //~| NOTE not found in this scope + use m; + { + let a3: BindingF = m!(); + } +} + +fn ff3() { + // fn f -> macro m -> let f + + { + let a0: FnF = m!(); + } + fn f() -> FnF { 42 } + { + let a1: FnF = m!(); + } + macro_rules! m {() => ( f() )} + use m; + { + let a2: FnF = m!(); + } + let f = || -> BindingF { 42 }; + { + let a3: FnF = m!(); + } +} + +fn ff4() { + // macro m -> fn f -> let f; + + { + let a0: FnF = m!(); + } + macro_rules! m {() => ( f() )} + use m; + { + let a1: FnF = m!(); + } + fn f() -> FnF { 42 } + { + let a2: FnF = m!(); + } + let f = || -> BindingF { 42 }; + { + let a3: FnF = m!(); + } +} + +fn ff5() { + // macro m -> let f -> fn f; + + { + let a0: FnF = m!(); + } + macro_rules! m {() => ( f() )} + use m; + { + let a1: FnF = m!(); + } + let f = || -> BindingF { 42 }; + { + let a2: FnF = m!(); + } + fn f() -> FnF { 42 } + { + let a3: FnF = m!(); + } +} + +fn f_with_macro_export0() { + { + let a: BindingF = 42; + let c0: BindingF = crate::m!(); + { + let d0: BindingF = m!(); + #[macro_export] + macro_rules! m { () => { a } } + use m; + let d1: BindingF = m!(); + } + let c1: BindingF = crate::m!(); + } + crate::m!(); // TODO: error +} + +fn f_with_macro_export1() { + fn f() {}; + { + let a: BindingF = 42; + let c0: BindingF = crate::m!(); + { + let d0: BindingF = m!(); + #[macro_export] + macro_rules! m { () => { a } } + use m; + let d1: BindingF = m!(); + } + let c1: BindingF = crate::m!(); + } + crate::m!(); // TODO: error +} + +fn main () {} diff --git a/tests/ui/resolve/fresh-should-shadow-definitation-in-macro-expand-in-block.stderr b/tests/ui/resolve/fresh-should-shadow-definitation-in-macro-expand-in-block.stderr new file mode 100644 index 0000000000000..a0e609f26b385 --- /dev/null +++ b/tests/ui/resolve/fresh-should-shadow-definitation-in-macro-expand-in-block.stderr @@ -0,0 +1,47 @@ +error[E0425]: cannot find function `f` in this scope + --> $DIR/fresh-should-shadow-definitation-in-macro-expand-in-block.rs:36:29 + | +LL | let a0: BindingF = m!(); + | ---- in this macro invocation +... +LL | macro_rules! m {() => ( f() )} + | ^ not found in this scope + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find function `f` in this scope + --> $DIR/fresh-should-shadow-definitation-in-macro-expand-in-block.rs:62:29 + | +LL | let a0: BindingF = m!(); + | ---- in this macro invocation +... +LL | macro_rules! m {() => ( f() )} + | ^ not found in this scope + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find function `f` in this scope + --> $DIR/fresh-should-shadow-definitation-in-macro-expand-in-block.rs:84:29 + | +LL | let a0: BindingF = m!(); + | ---- in this macro invocation +... +LL | macro_rules! m {() => ( f() )} + | ^ not found in this scope + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find function `f` in this scope + --> $DIR/fresh-should-shadow-definitation-in-macro-expand-in-block.rs:84:29 + | +LL | let a1: BindingF = m!(); + | ---- in this macro invocation +... +LL | macro_rules! m {() => ( f() )} + | ^ not found in this scope + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/fresh-should-shadow-definitation-in-macro-expand.rs b/tests/ui/resolve/fresh-should-shadow-definitation-in-macro-expand.rs new file mode 100644 index 0000000000000..ed1b6251ccab6 --- /dev/null +++ b/tests/ui/resolve/fresh-should-shadow-definitation-in-macro-expand.rs @@ -0,0 +1,205 @@ +//@ edition:2018 + +// issue#95237 + +type FnF = i8; +type BindingF = i16; + +fn f_without_definition_f0() { + // let f -> macro m + let f = || -> BindingF { 42 }; + let a0: BindingF = m!(); + macro_rules! m {() => ( f() )} + use m; + let a1: BindingF = m!(); +} + +fn f_without_definition_f1() { + // macro m -> let f + let a: BindingF = m!(); //~ NOTE in this expansion of m! + macro_rules! m {() => ( f() )} //~ ERROR cannot find function `f` in this scope + //~| NOTE not found in this scope + use m; + let f = || -> BindingF { 42 }; +} + +fn f_without_closure_f0() { + // fn f -> macro f + fn f() -> FnF { 42 } + let a: FnF = m!(); + macro_rules! m {() => ( f() )} + use m; +} + +fn f_without_closure_f1() { + // macro f -> fn f + let a: FnF = m!(); + macro_rules! m {() => ( f() )} + use m; + fn f() -> FnF { 42 } +} + +fn ff0() { + // let f -> macro m -> fn f + + let a0: BindingF = m!(); //~ NOTE in this expansion of m! + let f = || -> BindingF { 42 }; + let a1: BindingF = m!(); + macro_rules! m {() => ( f() )} //~ ERROR cannot find function `f` in this scope + //~| NOTE not found in this scope + use m; + let a2: BindingF = m!(); + fn f() -> FnF { 42 } + let a3: BindingF = m!(); +} + +fn ff1() { + // let f -> fn f -> macro m + + let a0: BindingF = m!(); //~ NOTE in this expansion of m! + let f = || -> BindingF { 42 }; + let a1: BindingF = m!(); + fn f() -> FnF { 42 } + let a2: BindingF = m!(); + macro_rules! m {() => ( f() )} //~ ERROR cannot find function `f` in this scope + //~| NOTE not found in this scope + use m; + let a3: BindingF = m!(); +} + +fn ff2() { + // fn f -> let f -> macro m + + let a0: BindingF = m!(); //~ NOTE in this expansion of m! + fn f() -> FnF { 42 } + let a1: BindingF = m!(); //~ NOTE in this expansion of m! + let f = || -> BindingF { 42 }; + let a2: BindingF = m!(); + macro_rules! m {() => ( f() )} //~ ERROR cannot find function `f` in this scope + //~| ERROR cannot find function `f` in this scope + //~| NOTE not found in this scope + //~| NOTE not found in this scope + use m; + let a3: BindingF = m!(); +} + +fn ff3() { + // fn f -> macro m -> let f + + let a0: FnF = m!(); + fn f() -> FnF { 42 } + let a1: FnF = m!(); + macro_rules! m {() => ( f() )} + use m; + let a2: FnF = m!(); + let f = || -> BindingF { 42 }; + let a3: FnF = m!(); +} + +fn ff4() { + // macro m -> fn f -> let f; + + let a0: FnF = m!(); + macro_rules! m {() => ( f() )} + use m; + let a1: FnF = m!(); + fn f() -> FnF { 42 } + let a2: FnF = m!(); + let f = || -> BindingF { 42 }; + let a3: FnF = m!(); +} + +fn ff5() { + // macro m -> let f -> fn f; + + let a0: FnF = m!(); + macro_rules! m {() => ( f() )} + use m; + let a1: FnF = m!(); + let f = || -> BindingF { 42 }; + let a2: FnF = m!(); + fn f() -> FnF { 42 } + let a3: FnF = m!(); +} + +fn tuple_f() { + // fn f -> let f in tuple -> macro m + + let a0: BindingF = m!(); //~ NOTE in this expansion of m! + fn f() -> FnF { 42 } + let a1: BindingF = m!(); //~ NOTE in this expansion of m! + let (f, _) = (|| -> BindingF { 42 }, ()); + let a2: BindingF = m!(); + macro_rules! m {() => ( f() )} //~ ERROR cannot find function `f` in this scope + //~| ERROR cannot find function `f` in this scope + //~| NOTE not found in this scope + //~| NOTE not found in this scope + use m; + let a3: BindingF = m!(); +} + +fn multiple() { + fn f() -> FnF { 42 } + let f = || -> BindingF { 42 }; + + let m0_0: BindingF = m0!(); + let m1_0: BindingF = m1!(); + let m2_0: i32 = m2!(); //~ NOTE in this expansion of m2! + + macro_rules! m0 { + () => { f() } + } + macro_rules! m1 { + () => { f() } + } + + let m0_1: BindingF = m0!(); + let m1_1: BindingF = m1!(); + let m2_1: i32 = m2!(); //~ NOTE in this expansion of m2! + + let f = || -> i32 { 42 }; + + let m0_2: BindingF = m0!(); + let m1_2: BindingF = m1!(); + let m2_2: i32 = m2!(); + + macro_rules! m2 { + () => { f() } //~ ERROR cannot find function `f` in this scope + } //~| ERROR cannot find function `f` in this scope + //~| NOTE not found in this scope + //~| NOTE not found in this scope + + let m0_3: BindingF = m0!(); + let m1_3: BindingF = m1!(); + let m2_3: i32 = m2!(); + + use {m0, m1, m2}; +} + +fn f_with_macro_export() { + let a: BindingF = 42; + + #[macro_export] + macro_rules! m { () => { a } } //~ ERROR cannot find value `a` in this scope + //~| ERROR cannot find value `a` in this scope + //~| NOTE not found in this scope + //~| NOTE not found in this scope + let b: BindingF = crate::m!(); +} + +fn f_use_macro_export_1() { + fn a() {} + + crate::m!(); // TODO: Error +} + +fn f_use_macro_export_2() { + crate::m!(); //~ NOTE in this expansion of crate::m! +} + +fn f_use_macro_export_3() { + let a = 42; + crate::m!(); //~ NOTE in this expansion of crate::m! +} + +fn main() {} diff --git a/tests/ui/resolve/fresh-should-shadow-definitation-in-macro-expand.stderr b/tests/ui/resolve/fresh-should-shadow-definitation-in-macro-expand.stderr new file mode 100644 index 0000000000000..98872d06da874 --- /dev/null +++ b/tests/ui/resolve/fresh-should-shadow-definitation-in-macro-expand.stderr @@ -0,0 +1,91 @@ +error[E0425]: cannot find function `f` in this scope + --> $DIR/fresh-should-shadow-definitation-in-macro-expand.rs:28:29 + | +LL | let a0: BindingF = m!(); + | ---- in this macro invocation +... +LL | macro_rules! m {() => ( f() )} + | ^ not found in this scope + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find function `f` in this scope + --> $DIR/fresh-should-shadow-definitation-in-macro-expand.rs:44:29 + | +LL | let a0: BindingF = m!(); + | ---- in this macro invocation +... +LL | macro_rules! m {() => ( f() )} + | ^ not found in this scope + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find function `f` in this scope + --> $DIR/fresh-should-shadow-definitation-in-macro-expand.rs:58:29 + | +LL | let a0: BindingF = m!(); + | ---- in this macro invocation +... +LL | macro_rules! m {() => ( f() )} + | ^ not found in this scope + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find function `f` in this scope + --> $DIR/fresh-should-shadow-definitation-in-macro-expand.rs:58:29 + | +LL | let a1: BindingF = m!(); + | ---- in this macro invocation +... +LL | macro_rules! m {() => ( f() )} + | ^ not found in this scope + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find function `f` in this scope + --> $DIR/fresh-should-shadow-definitation-in-macro-expand.rs:113:29 + | +LL | let a0: BindingF = m!(); + | ---- in this macro invocation +... +LL | macro_rules! m {() => ( f() )} + | ^ not found in this scope + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find function `f` in this scope + --> $DIR/fresh-should-shadow-definitation-in-macro-expand.rs:113:29 + | +LL | let a1: BindingF = m!(); + | ---- in this macro invocation +... +LL | macro_rules! m {() => ( f() )} + | ^ not found in this scope + | + = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find function `f` in this scope + --> $DIR/fresh-should-shadow-definitation-in-macro-expand.rs:147:17 + | +LL | let m2_0: i32 = m2!(); + | ----- in this macro invocation +... +LL | () => { f() } + | ^ not found in this scope + | + = note: this error originates in the macro `m2` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0425]: cannot find function `f` in this scope + --> $DIR/fresh-should-shadow-definitation-in-macro-expand.rs:147:17 + | +LL | let m2_1: i32 = m2!(); + | ----- in this macro invocation +... +LL | () => { f() } + | ^ not found in this scope + | + = note: this error originates in the macro `m2` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0425`.