about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-07-30 05:37:34 +0200
committerGitHub <noreply@github.com>2019-07-30 05:37:34 +0200
commit652f13d838d7b017e2d0ce4bbdb3c4d7a1a866d9 (patch)
treedf311895c970ef1339ab6d6da7fe3ea4d406d18e /src
parent51e50ed82770e8e48960797d822841e333005202 (diff)
parent0fb9295e1231d0878ec3cd06811e3e0dc8c7ce4f (diff)
downloadrust-652f13d838d7b017e2d0ce4bbdb3c4d7a1a866d9.tar.gz
rust-652f13d838d7b017e2d0ce4bbdb3c4d7a1a866d9.zip
Rollup merge of #63083 - matthewjasper:parameter-hygiene, r=petrochenkov
Make generic parameters always use modern hygiene

* E0263 (lifetime parameter declared twice in the same scope) now compares modernized identifiers.
* Const parameters are now resolved with modern hygiene.

Closes #58307
Closes #60746
Closes #61574
Closes #62433
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/resolve_lifetime.rs2
-rw-r--r--src/librustc_resolve/lib.rs26
-rw-r--r--src/test/ui/hygiene/duplicate_lifetimes.rs19
-rw-r--r--src/test/ui/hygiene/duplicate_lifetimes.stderr27
-rw-r--r--src/test/ui/hygiene/generic_params.rs104
-rw-r--r--src/test/ui/hygiene/generic_params.stderr6
-rw-r--r--src/test/ui/hygiene/issue-61574-const-parameters.rs32
-rw-r--r--src/test/ui/hygiene/issue-61574-const-parameters.stderr6
-rw-r--r--src/test/ui/hygiene/ty_params.rs14
9 files changed, 213 insertions, 23 deletions
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index e2b1b54cef3..f6c62d191fa 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 bc5898fe78d..c8dd8282fd0 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 00000000000..e7312b51dbc
--- /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 00000000000..7aaea6ff24e
--- /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 00000000000..9dc5adfce47
--- /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<T: Clone>(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<T: Clone>(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<const $C: usize, const C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); $C], [(); C]) {
+            (t1, t2)
+        }
+    }
+
+    #[rustc_macro_transparency = "semitransparent"]
+    macro n($C:ident) {
+        fn g<const $C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) {
+            (t1, t2)
+        }
+        fn h<const C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) {
+            (t1, t2)
+        }
+    }
+
+    #[rustc_macro_transparency = "transparent"]
+    macro p($C:ident) {
+        fn j<const $C: usize>(t1: [(); $C], t2: [(); C]) -> ([(); C], [(); $C]) {
+            (t1, t2)
+        }
+        fn k<const C: usize>(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 00000000000..ecd228a5db5
--- /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 00000000000..dcfb42287d5
--- /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, const SIZE: usize>([T; {SIZE}]);
+
+macro_rules! impl_operator_overload {
+    ($trait_ident:ident, $method_ident:ident) => {
+
+        impl<T, const SIZE: usize> $trait_ident for VectorLike<T, {SIZE}>
+        where
+            T: $trait_ident,
+        {
+            type Output = VectorLike<T, {SIZE}>;
+
+            fn $method_ident(self, _: VectorLike<T, {SIZE}>) -> VectorLike<T, {SIZE}> {
+                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 00000000000..302b5fde887
--- /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 b296bfe5988..00000000000
--- 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>(t: T, t2: $T) -> (T, $T) {
-        (t, t2)
-    }
-}
-
-m!(T);
-
-fn main() {}