about summary refs log tree commit diff
path: root/src/librustc_parse/parser
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-01-21 19:42:20 +0100
committerGitHub <noreply@github.com>2020-01-21 19:42:20 +0100
commit3484e2fab4153068e4e5eaebab215e680efe38f1 (patch)
tree4955c22b712892f482ee718f954769726fd66baa /src/librustc_parse/parser
parentd532a04a1c6afb34c8b0ac5da3e2bbf76aad5800 (diff)
parent6bd69a10921785aa8ab68e58d9c7a7ea1ff6ef96 (diff)
downloadrust-3484e2fab4153068e4e5eaebab215e680efe38f1.tar.gz
rust-3484e2fab4153068e4e5eaebab215e680efe38f1.zip
Rollup merge of #68140 - ecstatic-morse:const-trait-bound-opt-out, r=oli-obk
Implement `?const` opt-out for trait bounds

For now, such bounds are treated exactly the same as unprefixed ones in all contexts. [RFC 2632](https://github.com/rust-lang/rfcs/pull/2632) does not specify whether such bounds are forbidden outside of `const` contexts, so they are allowed at the moment.

Prior to this PR, the constness of a trait bound/impl was stored in `TraitRef`. Now, the constness of an `impl` is stored in `ast::ItemKind::Impl` and the constness of a bound in `ast::TraitBoundModifer`. Additionally, constness of trait bounds is now stored in an additional field of `ty::Predicate::Trait`, and the combination of the constness of the item along with any `TraitBoundModifier` determines the constness of the bound in accordance with the RFC. Encoding the constness of impls at the `ty` level is left for a later PR.

After a discussion in \#wg-grammar on Discord, it was decided that the grammar should not encode the mutual exclusivity of trait bound modifiers. The grammar for trait bound modifiers remains `[?const] [?]`. To encode this, I add a dummy variant to `ast::TraitBoundModifier` that is used when the syntax `?const ?` appears. This variant causes an error in AST validation and disappears during HIR lowering.

cc #67794

r? @oli-obk
Diffstat (limited to 'src/librustc_parse/parser')
-rw-r--r--src/librustc_parse/parser/item.rs18
-rw-r--r--src/librustc_parse/parser/ty.rs18
2 files changed, 16 insertions, 20 deletions
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 5076aafe4eb..31db7fc5f75 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -4,7 +4,7 @@ use super::{FollowedByType, Parser, PathStyle};
 use crate::maybe_whole;
 
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, PResult, StashKey};
-use rustc_span::source_map::{self, respan, Span, Spanned};
+use rustc_span::source_map::{self, respan, Span};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::BytePos;
 use syntax::ast::{self, AttrKind, AttrStyle, AttrVec, Attribute, Ident, DUMMY_NODE_ID};
@@ -565,9 +565,9 @@ impl<'a> Parser<'a> {
         let constness = if self.eat_keyword(kw::Const) {
             let span = self.prev_span;
             self.sess.gated_spans.gate(sym::const_trait_impl, span);
-            Some(respan(span, Constness::Const))
+            Constness::Const
         } else {
-            None
+            Constness::NotConst
         };
 
         // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type.
@@ -630,13 +630,13 @@ impl<'a> Parser<'a> {
                         err_path(ty_first.span)
                     }
                 };
-                let constness = constness.map(|c| c.node);
-                let trait_ref = TraitRef { path, constness, ref_id: ty_first.id };
+                let trait_ref = TraitRef { path, ref_id: ty_first.id };
 
                 ItemKind::Impl {
                     unsafety,
                     polarity,
                     defaultness,
+                    constness,
                     generics,
                     of_trait: Some(trait_ref),
                     self_ty: ty_second,
@@ -644,18 +644,12 @@ impl<'a> Parser<'a> {
                 }
             }
             None => {
-                // Reject `impl const Type {}` here
-                if let Some(Spanned { node: Constness::Const, span }) = constness {
-                    self.struct_span_err(span, "`const` cannot modify an inherent impl")
-                        .help("only a trait impl can be `const`")
-                        .emit();
-                }
-
                 // impl Type
                 ItemKind::Impl {
                     unsafety,
                     polarity,
                     defaultness,
+                    constness,
                     generics,
                     of_trait: None,
                     self_ty: ty_first,
diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs
index d1875a6c940..a4cc9fa48f2 100644
--- a/src/librustc_parse/parser/ty.rs
+++ b/src/librustc_parse/parser/ty.rs
@@ -26,10 +26,12 @@ 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) -> TraitBoundModifier {
+        match (self.maybe, self.maybe_const) {
+            (None, None) => TraitBoundModifier::None,
+            (Some(_), None) => TraitBoundModifier::Maybe,
+            (None, Some(_)) => TraitBoundModifier::MaybeConst,
+            (Some(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe,
         }
     }
 }
@@ -214,7 +216,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
@@ -556,9 +558,9 @@ 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 = modifiers.to_trait_bound_modifier();
+        let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
+        Ok(GenericBound::Trait(poly_trait, modifier))
     }
 
     /// Optionally parses `for<$generic_params>`.