about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_ast_lowering/lib.rs8
-rw-r--r--src/librustc_ast_passes/ast_validation.rs20
-rw-r--r--src/librustc_hir/hir.rs1
-rw-r--r--src/librustc_parse/parser/ty.rs33
-rw-r--r--src/librustdoc/html/format.rs1
-rw-r--r--src/libsyntax/ast.rs11
6 files changed, 42 insertions, 32 deletions
diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs
index 76a0889c376..90560c371e2 100644
--- a/src/librustc_ast_lowering/lib.rs
+++ b/src/librustc_ast_lowering/lib.rs
@@ -1250,7 +1250,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     let bounds =
                         this.arena.alloc_from_iter(bounds.iter().filter_map(
                             |bound| match *bound {
-                                GenericBound::Trait(ref ty, TraitBoundModifier::None) => {
+                                GenericBound::Trait(ref ty, TraitBoundModifier::None)
+                                | GenericBound::Trait(ref ty, TraitBoundModifier::MaybeConst) => {
                                     Some(this.lower_poly_trait_ref(ty, itctx.reborrow()))
                                 }
                                 GenericBound::Trait(_, TraitBoundModifier::Maybe) => None,
@@ -2158,10 +2159,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         p: &PolyTraitRef,
         mut itctx: ImplTraitContext<'_, 'hir>,
     ) -> hir::PolyTraitRef<'hir> {
-        if p.trait_ref.constness.is_some() {
-            self.diagnostic().span_err(p.span, "`?const` on trait bounds is not yet implemented");
-        }
-
         let bound_generic_params = self.lower_generic_params(
             &p.bound_generic_params,
             &NodeMap::default(),
@@ -2301,6 +2298,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         match f {
             TraitBoundModifier::None => hir::TraitBoundModifier::None,
             TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe,
+            TraitBoundModifier::MaybeConst => hir::TraitBoundModifier::MaybeConst,
         }
     }
 
diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
index 7dbd2362f04..23cb9734833 100644
--- a/src/librustc_ast_passes/ast_validation.rs
+++ b/src/librustc_ast_passes/ast_validation.rs
@@ -917,22 +917,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
     }
 
     fn visit_param_bound(&mut self, bound: &'a GenericBound) {
-        if let GenericBound::Trait(poly, maybe_bound) = bound {
-            match poly.trait_ref.constness {
-                Some(Constness::NotConst) => {
-                    if *maybe_bound == TraitBoundModifier::Maybe {
-                        self.err_handler()
-                            .span_err(bound.span(), "`?const` and `?` are mutually exclusive");
-                    }
-
-                    if let Some(ctx) = self.bound_context {
-                        let msg = format!("`?const` is not permitted in {}", ctx.description());
-                        self.err_handler().span_err(bound.span(), &msg);
-                    }
-                }
-
-                Some(Constness::Const) => panic!("Parser should reject bare `const` on bounds"),
-                None => {}
+        if let GenericBound::Trait(_, TraitBoundModifier::MaybeConst) = bound {
+            if let Some(ctx) = self.bound_context {
+                let msg = format!("`?const` is not permitted in {}", ctx.description());
+                self.err_handler().span_err(bound.span(), &msg);
             }
         }
 
diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs
index d850cfe69ce..b62a7e413e3 100644
--- a/src/librustc_hir/hir.rs
+++ b/src/librustc_hir/hir.rs
@@ -364,6 +364,7 @@ impl GenericArgs<'_> {
 pub enum TraitBoundModifier {
     None,
     Maybe,
+    MaybeConst,
 }
 
 /// The AST represents all type param bounds as types.
diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs
index 065a3b14428..9c9180778e5 100644
--- a/src/librustc_parse/parser/ty.rs
+++ b/src/librustc_parse/parser/ty.rs
@@ -27,11 +27,17 @@ struct BoundModifiers {
 }
 
 impl BoundModifiers {
-    fn trait_bound_modifier(&self) -> TraitBoundModifier {
-        match self.maybe {
-            Some(_) => TraitBoundModifier::Maybe,
-            None => TraitBoundModifier::None,
-        }
+    fn to_trait_bound_modifier(&self) -> Result<TraitBoundModifier, &'static str> {
+        let modifier = match (self.maybe, self.maybe_const) {
+            (None, None) => TraitBoundModifier::None,
+            (Some(_), None) => TraitBoundModifier::Maybe,
+            (None, Some(_)) => TraitBoundModifier::MaybeConst,
+            (Some(_), Some(_)) => {
+                return Err("`?const` and `?` are mutually exclusive");
+            }
+        };
+
+        Ok(modifier)
     }
 }
 
@@ -215,7 +221,7 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, TyKind> {
         assert_ne!(self.token, token::Question);
 
-        let poly_trait_ref = PolyTraitRef::new(generic_params, path, None, lo.to(self.prev_span));
+        let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_span));
         let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)];
         if parse_plus {
             self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
@@ -557,9 +563,18 @@ impl<'a> Parser<'a> {
             self.expect(&token::CloseDelim(token::Paren))?;
         }
 
-        let constness = modifiers.maybe_const.map(|_| ast::Constness::NotConst);
-        let poly_trait = PolyTraitRef::new(lifetime_defs, path, constness, lo.to(self.prev_span));
-        Ok(GenericBound::Trait(poly_trait, modifiers.trait_bound_modifier()))
+        let modifier = match modifiers.to_trait_bound_modifier() {
+            Ok(m) => m,
+            Err(msg) => {
+                self.struct_span_err(lo.to(self.prev_span), msg).emit();
+
+                // Continue compilation as if the user had written `?Trait`.
+                TraitBoundModifier::Maybe
+            }
+        };
+
+        let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
+        Ok(GenericBound::Trait(poly_trait, modifier))
     }
 
     /// Optionally parses `for<$generic_params>`.
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 6434dccdfc7..79923fc3d36 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -361,6 +361,7 @@ impl clean::GenericBound {
                 let modifier_str = match modifier {
                     hir::TraitBoundModifier::None => "",
                     hir::TraitBoundModifier::Maybe => "?",
+                    hir::TraitBoundModifier::MaybeConst => "?const",
                 };
                 if f.alternate() {
                     write!(f, "{}{:#}", modifier_str, ty.print())
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 6b54893075e..ce4d9cca81e 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -266,12 +266,19 @@ pub const CRATE_NODE_ID: NodeId = NodeId::from_u32_const(0);
 /// small, positive ids.
 pub const DUMMY_NODE_ID: NodeId = NodeId::MAX;
 
-/// A modifier on a bound, currently this is only used for `?Sized`, where the
-/// modifier is `Maybe`. Negative bounds should also be handled here.
+/// A modifier on a bound, e.g., `?Sized` or `?const Trait`.
+///
+/// Negative bounds should also be handled here.
 #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
 pub enum TraitBoundModifier {
+    /// No modifiers
     None,
+
+    /// `?Trait`
     Maybe,
+
+    /// `?const Trait`
+    MaybeConst,
 }
 
 /// The AST represents all type param bounds as types.