about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJack Huey <jack.huey@umassmed.edu>2021-05-15 15:19:01 -0400
committerJack Huey <jack.huey@umassmed.edu>2021-05-15 15:52:39 -0400
commit0daabbee2d255ec78811443cdc4def67b3e0de1d (patch)
tree186a5dcf3caadefd4957f657360ce6fb4862181c
parentc34e7c60f5b0d3e860b5b26191535a86fb649dba (diff)
downloadrust-0daabbee2d255ec78811443cdc4def67b3e0de1d.tar.gz
rust-0daabbee2d255ec78811443cdc4def67b3e0de1d.zip
Change to just use first binders and add test
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs73
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs4
-rw-r--r--src/test/ui/symbol-names/trait-objects.legacy.stderr56
-rw-r--r--src/test/ui/symbol-names/trait-objects.rs56
-rw-r--r--src/test/ui/symbol-names/trait-objects.v0.stderr56
5 files changed, 218 insertions, 27 deletions
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index c0690d93c96..a70b374fc6d 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -485,38 +485,59 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
         mut self,
         predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
     ) -> Result<Self::DynExistential, Self::Error> {
-        let mut predicate_iter = predicates.iter().peekable();
-        while let Some(predicate) = predicate_iter.next() {
-            match predicate.as_ref().skip_binder() {
-                ty::ExistentialPredicate::Trait(trait_ref) => {
-                    self = self.in_binder(&predicate, |mut cx, _predicate| {
+        // Okay, so this is a bit tricky. Imagine we have a trait object like
+        // `dyn for<'a> Foo<'a, Bar = &'a ()>`. When we mangle this, the
+        // output looks really close to the syntax, where the `Bar = &'a ()` bit
+        // is under the same binders (`['a]`) as the `Foo<'a>` bit. However, we
+        // actually desugar these into two separate `ExistentialPredicate`s. We
+        // can't enter/exit the "binder scope" twice though, because then we
+        // would mangle the binders twice. (Also, side note, we merging these
+        // two is kind of difficult, because of potential HRTBs in the Projection
+        // predicate.)
+        //
+        // Also worth mentioning: imagine that we instead had
+        // `dyn for<'a> Foo<'a, Bar = &'a ()> + Send`. In this case, `Send` is
+        // under the same binders as `Foo`. Currently, this doesn't matter,
+        // because only *auto traits* are allowed other than the principal trait
+        // and all auto traits don't have any generics. Two things could
+        // make this not an "okay" mangling:
+        // 1) Instead of mangling only *used*
+        // bound vars, we want to mangle *all* bound vars (`for<'b> Send` is a
+        // valid trait predicate);
+        // 2) We allow multiple "principal" traits in the future, or at least
+        // allow in any form another trait predicate that can take generics.
+        //
+        // Here we assume that predicates have the following structure:
+        // [<Trait> [{<Projection>}]] [{<Auto>}]
+        // Since any predicates after the first one shouldn't change the binders,
+        // just put them all in the binders of the first.
+        self = self.in_binder(&predicates[0], |mut cx, _| {
+            for predicate in predicates.iter() {
+                // It would be nice to be able to validate bound vars here, but
+                // projections can actually include bound vars from super traits
+                // because of HRTBs (only in the `Self` type). Also, auto traits
+                // could have different bound vars *anyways*.
+                match predicate.as_ref().skip_binder() {
+                    ty::ExistentialPredicate::Trait(trait_ref) => {
                         // Use a type that can't appear in defaults of type parameters.
                         let dummy_self = cx.tcx.mk_ty_infer(ty::FreshTy(0));
                         let trait_ref = trait_ref.with_self_ty(cx.tcx, dummy_self);
                         cx = cx.print_def_path(trait_ref.def_id, trait_ref.substs)?;
-                        while let Some(projection_pred) = predicate_iter.next_if(|p| {
-                            matches!(p.skip_binder(), ty::ExistentialPredicate::Projection(_))
-                        }) {
-                            let projection = match projection_pred.skip_binder() {
-                                ty::ExistentialPredicate::Projection(projection) => projection,
-                                _ => unreachable!(),
-                            };
-                            let name = cx.tcx.associated_item(projection.item_def_id).ident;
-                            cx.push("p");
-                            cx.push_ident(&name.as_str());
-                            cx = projection.ty.print(cx)?;
-                        }
-                        Ok(cx)
-                    })?;
-                }
-                ty::ExistentialPredicate::Projection(_) => {
-                    unreachable!("handled in trait predicate arm")
-                }
-                ty::ExistentialPredicate::AutoTrait(def_id) => {
-                    self = self.print_def_path(*def_id, &[])?;
+                    }
+                    ty::ExistentialPredicate::Projection(projection) => {
+                        let name = cx.tcx.associated_item(projection.item_def_id).ident;
+                        cx.push("p");
+                        cx.push_ident(&name.as_str());
+                        cx = projection.ty.print(cx)?;
+                    }
+                    ty::ExistentialPredicate::AutoTrait(def_id) => {
+                        cx = cx.print_def_path(*def_id, &[])?;
+                    }
                 }
             }
-        }
+            Ok(cx)
+        })?;
+
         self.push("E");
         Ok(self)
     }
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 2f2e90e4bd6..c2e451670ed 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -1386,11 +1386,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| {
             ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id()))
         });
+        // N.b. principal, projections, auto traits
+        // FIXME: This is actually wrong with multiple principals in regards to symbol mangling
         let mut v = regular_trait_predicates
-            .chain(auto_trait_predicates)
             .chain(
                 existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)),
             )
+            .chain(auto_trait_predicates)
             .collect::<SmallVec<[_; 8]>>();
         v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
         v.dedup();
diff --git a/src/test/ui/symbol-names/trait-objects.legacy.stderr b/src/test/ui/symbol-names/trait-objects.legacy.stderr
new file mode 100644
index 00000000000..200280c358f
--- /dev/null
+++ b/src/test/ui/symbol-names/trait-objects.legacy.stderr
@@ -0,0 +1,56 @@
+error: symbol-name(_ZN136_$LT$$RF$dyn$u20$core..ops..function..FnMut$LT$$LP$$RF$u8$C$$RP$$GT$$u2b$Output$u20$$u3d$$u20$$LP$$RP$$u20$as$u20$trait_objects..Bar$GT$6method17h1e14a5f2d365272fE)
+  --> $DIR/trait-objects.rs:15:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<&dyn core::ops::function::FnMut<(&u8,)>+Output = () as trait_objects::Bar>::method::h1e14a5f2d365272f)
+  --> $DIR/trait-objects.rs:15:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<&dyn core::ops::function::FnMut<(&u8,)>+Output = () as trait_objects::Bar>::method)
+  --> $DIR/trait-objects.rs:15:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_ZN159_$LT$$RF$dyn$u20$core..ops..function..FnMut$LT$$LP$$RF$u8$C$$RP$$GT$$u2b$Output$u20$$u3d$$u20$$LP$$RP$$u2b$core..marker..Send$u20$as$u20$trait_objects..Foo$GT$6method17he7a07961c9aaa367E)
+  --> $DIR/trait-objects.rs:30:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<&dyn core::ops::function::FnMut<(&u8,)>+Output = ()+core::marker::Send as trait_objects::Foo>::method::he7a07961c9aaa367)
+  --> $DIR/trait-objects.rs:30:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<&dyn core::ops::function::FnMut<(&u8,)>+Output = ()+core::marker::Send as trait_objects::Foo>::method)
+  --> $DIR/trait-objects.rs:30:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_ZN159_$LT$$RF$dyn$u20$core..ops..function..FnMut$LT$$LP$$RF$u8$C$$RP$$GT$$u2b$Output$u20$$u3d$$u20$$LP$$RP$$u2b$core..marker..Send$u20$as$u20$trait_objects..Baz$GT$6method17ha53e6f99bf033f0bE)
+  --> $DIR/trait-objects.rs:45:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<&dyn core::ops::function::FnMut<(&u8,)>+Output = ()+core::marker::Send as trait_objects::Baz>::method::ha53e6f99bf033f0b)
+  --> $DIR/trait-objects.rs:45:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<&dyn core::ops::function::FnMut<(&u8,)>+Output = ()+core::marker::Send as trait_objects::Baz>::method)
+  --> $DIR/trait-objects.rs:45:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
diff --git a/src/test/ui/symbol-names/trait-objects.rs b/src/test/ui/symbol-names/trait-objects.rs
new file mode 100644
index 00000000000..ffbd3901b8e
--- /dev/null
+++ b/src/test/ui/symbol-names/trait-objects.rs
@@ -0,0 +1,56 @@
+// Ensure that trait objects don't include more than one binder. See #83611
+
+// build-fail
+// revisions: legacy v0
+//[legacy]compile-flags: -Z symbol-mangling-version=legacy
+    //[v0]compile-flags: -Z symbol-mangling-version=v0
+
+#![feature(rustc_attrs)]
+
+trait Bar {
+    fn method(&self) {}
+}
+
+impl Bar for &dyn FnMut(&u8) {
+    #[rustc_symbol_name]
+    //[legacy]~^ ERROR symbol-name
+    //[legacy]~| ERROR demangling
+    //[legacy]~| ERROR demangling-alt
+    //[v0]~^^^^ ERROR symbol-name
+    //[v0]~| ERROR demangling
+    //[v0]~| ERROR demangling-alt
+    fn method(&self) {}
+}
+
+trait Foo {
+    fn method(&self) {}
+}
+
+impl Foo for &(dyn FnMut(&u8) + for<'b> Send) {
+    #[rustc_symbol_name]
+    //[legacy]~^ ERROR symbol-name
+    //[legacy]~| ERROR demangling
+    //[legacy]~| ERROR demangling-alt
+    //[v0]~^^^^ ERROR symbol-name
+    //[v0]~| ERROR demangling
+    //[v0]~| ERROR demangling-alt
+    fn method(&self) {}
+}
+
+trait Baz {
+    fn method(&self) {}
+}
+
+impl Baz for &(dyn for<'b> Send + FnMut(&u8)) {
+    #[rustc_symbol_name]
+    //[legacy]~^ ERROR symbol-name
+    //[legacy]~| ERROR demangling
+    //[legacy]~| ERROR demangling-alt
+    //[v0]~^^^^ ERROR symbol-name
+    //[v0]~| ERROR demangling
+    //[v0]~| ERROR demangling-alt
+    fn method(&self) {}
+}
+
+fn main() {
+}
diff --git a/src/test/ui/symbol-names/trait-objects.v0.stderr b/src/test/ui/symbol-names/trait-objects.v0.stderr
new file mode 100644
index 00000000000..7a29f44718a
--- /dev/null
+++ b/src/test/ui/symbol-names/trait-objects.v0.stderr
@@ -0,0 +1,56 @@
+error: symbol-name(_RNvXCs21hi0yVfW1J_13trait_objectsRDG_INtNtNtCs54lBhuwykzk_4core3ops8function5FnMutTRL0_hEEp6OutputuEL_NtB2_3Bar6method)
+  --> $DIR/trait-objects.rs:15:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<&dyn for<'a> core[3b0e14d6e1ad42d0]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[17891616a171812d]::Bar>::method)
+  --> $DIR/trait-objects.rs:15:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects::Bar>::method)
+  --> $DIR/trait-objects.rs:15:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RNvXs_Cs21hi0yVfW1J_13trait_objectsRDG_INtNtNtCs54lBhuwykzk_4core3ops8function5FnMutTRL0_hEEp6OutputuNtNtBI_6marker4SendEL_NtB4_3Foo6method)
+  --> $DIR/trait-objects.rs:30:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<&dyn for<'a> core[3b0e14d6e1ad42d0]::ops::function::FnMut<(&'a u8,), Output = ()> + core[3b0e14d6e1ad42d0]::marker::Send as trait_objects[17891616a171812d]::Foo>::method)
+  --> $DIR/trait-objects.rs:30:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> + core::marker::Send as trait_objects::Foo>::method)
+  --> $DIR/trait-objects.rs:30:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RNvXs0_Cs21hi0yVfW1J_13trait_objectsRDG_INtNtNtCs54lBhuwykzk_4core3ops8function5FnMutTRL0_hEEp6OutputuNtNtBJ_6marker4SendEL_NtB5_3Baz6method)
+  --> $DIR/trait-objects.rs:45:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<&dyn for<'a> core[3b0e14d6e1ad42d0]::ops::function::FnMut<(&'a u8,), Output = ()> + core[3b0e14d6e1ad42d0]::marker::Send as trait_objects[17891616a171812d]::Baz>::method)
+  --> $DIR/trait-objects.rs:45:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> + core::marker::Send as trait_objects::Baz>::method)
+  --> $DIR/trait-objects.rs:45:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+