diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index e2b1b54cef39f..f6c62d191fa62 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -2568,7 +2568,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let lifetimes: Vec<_> = params .iter() .filter_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => Some((param, param.name)), + GenericParamKind::Lifetime { .. } => Some((param, param.name.modern())), _ => None, }) .collect(); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index bc5898fe78da7..c8dd8282fd0f9 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -869,8 +869,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { debug!("(resolving function) entering function"); let rib_kind = match function_kind { FnKind::ItemFn(..) => FnItemRibKind, - FnKind::Method(..) => AssocItemRibKind, - FnKind::Closure(_) => NormalRibKind, + FnKind::Method(..) | FnKind::Closure(_) => NormalRibKind, }; // Create a value rib for the function. @@ -2307,21 +2306,32 @@ impl<'a> Resolver<'a> { if ident.name == kw::Invalid { return Some(LexicalScopeBinding::Res(Res::Err)); } - ident.span = if ident.name == kw::SelfUpper { + let (general_span, modern_span) = if ident.name == kw::SelfUpper { // FIXME(jseyfried) improve `Self` hygiene - ident.span.with_ctxt(SyntaxContext::empty()) + let empty_span = ident.span.with_ctxt(SyntaxContext::empty()); + (empty_span, empty_span) } else if ns == TypeNS { - ident.span.modern() + let modern_span = ident.span.modern(); + (modern_span, modern_span) } else { - ident.span.modern_and_legacy() + (ident.span.modern_and_legacy(), ident.span.modern()) }; + ident.span = general_span; + let modern_ident = Ident { span: modern_span, ..ident }; // Walk backwards up the ribs in scope. let record_used = record_used_id.is_some(); let mut module = self.graph_root; for i in (0 .. self.ribs[ns].len()).rev() { debug!("walk rib\n{:?}", self.ribs[ns][i].bindings); - if let Some(res) = self.ribs[ns][i].bindings.get(&ident).cloned() { + // Use the rib kind to determine whether we are resolving parameters + // (modern hygiene) or local variables (legacy hygiene). + let rib_ident = if let AssocItemRibKind | ItemRibKind = self.ribs[ns][i].kind { + modern_ident + } else { + ident + }; + if let Some(res) = self.ribs[ns][i].bindings.get(&rib_ident).cloned() { // The ident resolves to a type parameter or local variable. return Some(LexicalScopeBinding::Res( self.validate_res_from_ribs(ns, i, res, record_used, path_span), @@ -2357,7 +2367,7 @@ impl<'a> Resolver<'a> { } } - ident.span = ident.span.modern(); + ident = modern_ident; let mut poisoned = None; loop { let opt_module = if let Some(node_id) = record_used_id { diff --git a/src/test/ui/hygiene/duplicate_lifetimes.rs b/src/test/ui/hygiene/duplicate_lifetimes.rs new file mode 100644 index 0000000000000..e7312b51dbcb8 --- /dev/null +++ b/src/test/ui/hygiene/duplicate_lifetimes.rs @@ -0,0 +1,19 @@ +// Ensure that lifetime parameter names are modernized before we check for +// duplicates. + +#![feature(decl_macro, rustc_attrs)] + +#[rustc_macro_transparency = "semitransparent"] +macro m($a:lifetime) { + fn g<$a, 'a>() {} //~ ERROR lifetime name `'a` declared twice +} + +#[rustc_macro_transparency = "transparent"] +macro n($a:lifetime) { + fn h<$a, 'a>() {} //~ ERROR lifetime name `'a` declared twice +} + +m!('a); +n!('a); + +fn main() {} diff --git a/src/test/ui/hygiene/duplicate_lifetimes.stderr b/src/test/ui/hygiene/duplicate_lifetimes.stderr new file mode 100644 index 0000000000000..7aaea6ff24e39 --- /dev/null +++ b/src/test/ui/hygiene/duplicate_lifetimes.stderr @@ -0,0 +1,27 @@ +error[E0263]: lifetime name `'a` declared twice in the same scope + --> $DIR/duplicate_lifetimes.rs:8:14 + | +LL | fn g<$a, 'a>() {} + | ^^ declared twice +... +LL | m!('a); + | ------- + | | | + | | previous declaration here + | in this macro invocation + +error[E0263]: lifetime name `'a` declared twice in the same scope + --> $DIR/duplicate_lifetimes.rs:13:14 + | +LL | fn h<$a, 'a>() {} + | ^^ declared twice +... +LL | n!('a); + | ------- + | | | + | | previous declaration here + | in this macro invocation + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0263`. diff --git a/src/test/ui/hygiene/generic_params.rs b/src/test/ui/hygiene/generic_params.rs new file mode 100644 index 0000000000000..9dc5adfce478a --- /dev/null +++ b/src/test/ui/hygiene/generic_params.rs @@ -0,0 +1,104 @@ +// Ensure that generic parameters always have modern hygiene. + +// check-pass +// ignore-pretty pretty-printing is unhygienic + +#![feature(decl_macro, rustc_attrs, const_generics)] + +mod type_params { + macro m($T:ident) { + fn f<$T: Clone, T: PartialEq>(t1: $T, t2: T) -> ($T, bool) { + (t1.clone(), t2 == t2) + } + } + + #[rustc_macro_transparency = "semitransparent"] + macro n($T:ident) { + fn g<$T: Clone>(t1: $T, t2: T) -> (T, $T) { + (t1.clone(), t2.clone()) + } + fn h(t1: $T, t2: T) -> (T, $T) { + (t1.clone(), t2.clone()) + } + } + + #[rustc_macro_transparency = "transparent"] + macro p($T:ident) { + fn j<$T: Clone>(t1: $T, t2: T) -> (T, $T) { + (t1.clone(), t2.clone()) + } + fn k(t1: $T, t2: T) -> (T, $T) { + (t1.clone(), t2.clone()) + } + } + + m!(T); + n!(T); + p!(T); +} + +mod lifetime_params { + macro m($a:lifetime) { + fn f<'b, 'c, $a: 'b, 'a: 'c>(t1: &$a(), t2: &'a ()) -> (&'b (), &'c ()) { + (t1, t2) + } + } + + #[rustc_macro_transparency = "semitransparent"] + macro n($a:lifetime) { + fn g<$a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { + (t1, t2) + } + fn h<'a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { + (t1, t2) + } + } + + #[rustc_macro_transparency = "transparent"] + macro p($a:lifetime) { + fn j<$a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { + (t1, t2) + } + fn k<'a>(t1: &$a(), t2: &'a ()) -> (&'a (), &$a ()) { + (t1, t2) + } + } + + m!('a); + n!('a); + p!('a); +} + +mod const_params { + macro m($C:ident) { + fn f(t1: [(); $C], t2: [(); C]) -> ([(); $C], [(); C]) { + (t1, t2) + } + } + + #[rustc_macro_transparency = "semitransparent"] + macro n($C:ident) { + fn g(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { + (t1, t2) + } + fn h(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { + (t1, t2) + } + } + + #[rustc_macro_transparency = "transparent"] + macro p($C:ident) { + fn j(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { + (t1, t2) + } + fn k(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) { + (t1, t2) + } + } + + m!(C); + n!(C); + p!(C); +} + +fn main() {} diff --git a/src/test/ui/hygiene/generic_params.stderr b/src/test/ui/hygiene/generic_params.stderr new file mode 100644 index 0000000000000..ecd228a5db5c8 --- /dev/null +++ b/src/test/ui/hygiene/generic_params.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/generic_params.rs:6:37 + | +LL | #![feature(decl_macro, rustc_attrs, const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/hygiene/issue-61574-const-parameters.rs b/src/test/ui/hygiene/issue-61574-const-parameters.rs new file mode 100644 index 0000000000000..dcfb42287d5cb --- /dev/null +++ b/src/test/ui/hygiene/issue-61574-const-parameters.rs @@ -0,0 +1,32 @@ +// A more comprehensive test that const parameters have correctly implemented +// hygiene + +// check-pass + +#![feature(const_generics)] + +use std::ops::Add; + +struct VectorLike([T; {SIZE}]); + +macro_rules! impl_operator_overload { + ($trait_ident:ident, $method_ident:ident) => { + + impl $trait_ident for VectorLike + where + T: $trait_ident, + { + type Output = VectorLike; + + fn $method_ident(self, _: VectorLike) -> VectorLike { + let _ = SIZE; + unimplemented!() + } + } + + } +} + +impl_operator_overload!(Add, add); + +fn main() {} diff --git a/src/test/ui/hygiene/issue-61574-const-parameters.stderr b/src/test/ui/hygiene/issue-61574-const-parameters.stderr new file mode 100644 index 0000000000000..302b5fde8879c --- /dev/null +++ b/src/test/ui/hygiene/issue-61574-const-parameters.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/issue-61574-const-parameters.rs:6:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/hygiene/ty_params.rs b/src/test/ui/hygiene/ty_params.rs deleted file mode 100644 index b296bfe598887..0000000000000 --- a/src/test/ui/hygiene/ty_params.rs +++ /dev/null @@ -1,14 +0,0 @@ -// check-pass -// ignore-pretty pretty-printing is unhygienic - -#![feature(decl_macro)] - -macro m($T:ident) { - fn f(t: T, t2: $T) -> (T, $T) { - (t, t2) - } -} - -m!(T); - -fn main() {}