about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs39
-rw-r--r--src/test/ui/parser/trait-object-delimiters.rs17
-rw-r--r--src/test/ui/parser/trait-object-delimiters.stderr77
3 files changed, 130 insertions, 3 deletions
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 0f7b8ebd376..d537741c749 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -470,7 +470,7 @@ impl<'a> Parser<'a> {
     /// Is a `dyn B0 + ... + Bn` type allowed here?
     fn is_explicit_dyn_type(&mut self) -> bool {
         self.check_keyword(kw::Dyn)
-            && (self.token.uninterpolated_span().rust_2018()
+            && (!self.token.uninterpolated_span().rust_2015()
                 || self.look_ahead(1, |t| {
                     t.can_begin_bound() && !can_continue_type_after_non_fn_ident(t)
                 }))
@@ -539,7 +539,21 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, GenericBounds> {
         let mut bounds = Vec::new();
         let mut negative_bounds = Vec::new();
-        while self.can_begin_bound() {
+
+        while self.can_begin_bound() || self.token.is_keyword(kw::Dyn) {
+            if self.token.is_keyword(kw::Dyn) {
+                // Account for `&dyn Trait + dyn Other`.
+                self.struct_span_err(self.token.span, "invalid `dyn` keyword")
+                    .help("`dyn` is only needed at the start of a trait `+`-separated list")
+                    .span_suggestion(
+                        self.token.span,
+                        "remove this keyword",
+                        String::new(),
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+                self.bump();
+            }
             match self.parse_generic_bound()? {
                 Ok(bound) => bounds.push(bound),
                 Err(neg_sp) => negative_bounds.push(neg_sp),
@@ -721,7 +735,26 @@ impl<'a> Parser<'a> {
         let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
         let path = self.parse_path(PathStyle::Type)?;
         if has_parens {
-            self.expect(&token::CloseDelim(token::Paren))?;
+            if self.token.is_like_plus() {
+                // Someone has written something like `&dyn (Trait + Other)`. The correct code
+                // would be `&(dyn Trait + Other)`, but we don't have access to the appropriate
+                // span to suggest that. When written as `&dyn Trait + Other`, an appropriate
+                // suggestion is given.
+                let bounds = vec![];
+                self.parse_remaining_bounds(bounds, true)?;
+                self.expect(&token::CloseDelim(token::Paren))?;
+                let sp = vec![lo, self.prev_token.span];
+                let sugg: Vec<_> = sp.iter().map(|sp| (*sp, String::new())).collect();
+                self.struct_span_err(sp, "incorrect braces around trait bounds")
+                    .multipart_suggestion(
+                        "remove the parentheses",
+                        sugg,
+                        Applicability::MachineApplicable,
+                    )
+                    .emit();
+            } else {
+                self.expect(&token::CloseDelim(token::Paren))?;
+            }
         }
 
         let modifier = modifiers.to_trait_bound_modifier();
diff --git a/src/test/ui/parser/trait-object-delimiters.rs b/src/test/ui/parser/trait-object-delimiters.rs
new file mode 100644
index 00000000000..650ab572261
--- /dev/null
+++ b/src/test/ui/parser/trait-object-delimiters.rs
@@ -0,0 +1,17 @@
+// edition:2018
+
+fn foo1(_: &dyn Drop + AsRef<str>) {} //~ ERROR ambiguous `+` in a type
+//~^ ERROR only auto traits can be used as additional traits in a trait object
+
+fn foo2(_: &dyn (Drop + AsRef<str>)) {} //~ ERROR incorrect braces around trait bounds
+
+fn foo3(_: &dyn {Drop + AsRef<str>}) {} //~ ERROR expected parameter name, found `{`
+//~^ ERROR expected one of `!`, `(`, `)`, `,`, `?`, `for`, lifetime, or path, found `{`
+//~| ERROR at least one trait is required for an object type
+
+fn foo4(_: &dyn <Drop + AsRef<str>>) {} //~ ERROR expected identifier, found `<`
+
+fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {} //~ ERROR invalid `dyn` keyword
+//~^ ERROR only auto traits can be used as additional traits in a trait object
+
+fn main() {}
diff --git a/src/test/ui/parser/trait-object-delimiters.stderr b/src/test/ui/parser/trait-object-delimiters.stderr
new file mode 100644
index 00000000000..18b1b24122e
--- /dev/null
+++ b/src/test/ui/parser/trait-object-delimiters.stderr
@@ -0,0 +1,77 @@
+error: ambiguous `+` in a type
+  --> $DIR/trait-object-delimiters.rs:3:13
+   |
+LL | fn foo1(_: &dyn Drop + AsRef<str>) {}
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(dyn Drop + AsRef<str>)`
+
+error: incorrect braces around trait bounds
+  --> $DIR/trait-object-delimiters.rs:6:17
+   |
+LL | fn foo2(_: &dyn (Drop + AsRef<str>)) {}
+   |                 ^                 ^
+   |
+help: remove the parentheses
+   |
+LL | fn foo2(_: &dyn Drop + AsRef<str>) {}
+   |                --               --
+
+error: expected parameter name, found `{`
+  --> $DIR/trait-object-delimiters.rs:8:17
+   |
+LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
+   |                 ^ expected parameter name
+
+error: expected one of `!`, `(`, `)`, `,`, `?`, `for`, lifetime, or path, found `{`
+  --> $DIR/trait-object-delimiters.rs:8:17
+   |
+LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
+   |                -^ expected one of 8 possible tokens
+   |                |
+   |                help: missing `,`
+
+error: expected identifier, found `<`
+  --> $DIR/trait-object-delimiters.rs:12:17
+   |
+LL | fn foo4(_: &dyn <Drop + AsRef<str>>) {}
+   |                 ^ expected identifier
+
+error: invalid `dyn` keyword
+  --> $DIR/trait-object-delimiters.rs:14:25
+   |
+LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
+   |                         ^^^ help: remove this keyword
+   |
+   = help: `dyn` is only needed at the start of a trait `+`-separated list
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-object-delimiters.rs:3:24
+   |
+LL | fn foo1(_: &dyn Drop + AsRef<str>) {}
+   |                 ----   ^^^^^^^^^^ additional non-auto trait
+   |                 |
+   |                 first non-auto trait
+   |
+   = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Drop + AsRef<str> {}`
+   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
+
+error[E0224]: at least one trait is required for an object type
+  --> $DIR/trait-object-delimiters.rs:8:13
+   |
+LL | fn foo3(_: &dyn {Drop + AsRef<str>}) {}
+   |             ^^^
+
+error[E0225]: only auto traits can be used as additional traits in a trait object
+  --> $DIR/trait-object-delimiters.rs:14:29
+   |
+LL | fn foo5(_: &(dyn Drop + dyn AsRef<str>)) {}
+   |                  ----       ^^^^^^^^^^ additional non-auto trait
+   |                  |
+   |                  first non-auto trait
+   |
+   = help: consider creating a new trait with all of these as super-traits and using that trait here instead: `trait NewTrait: Drop + AsRef<str> {}`
+   = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0224, E0225.
+For more information about an error, try `rustc --explain E0224`.