From 01cbe506f99aa484f583a7affb65d15a839d2412 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 13 Jan 2020 20:30:23 -0800 Subject: Add `constness` field to `ast::ItemKind::Impl` --- src/librustc_parse/parser/item.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/librustc_parse/parser') diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 1921a6c8506..e4982896376 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -638,6 +638,7 @@ impl<'a> Parser<'a> { unsafety, polarity, defaultness, + constness, generics, of_trait: Some(trait_ref), self_ty: ty_second, @@ -657,6 +658,7 @@ impl<'a> Parser<'a> { unsafety, polarity, defaultness, + constness, generics, of_trait: None, self_ty: ty_first, -- cgit 1.4.1-3-g733a5 From 958b0bc8d22633927796502b13a7ce944100dec5 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 13 Jan 2020 20:30:25 -0800 Subject: Store `impl const` in `ItemKind::Impl` --- src/librustc_ast_passes/ast_validation.rs | 10 ++++++++-- src/librustc_parse/parser/item.rs | 16 ++++------------ 2 files changed, 12 insertions(+), 14 deletions(-) (limited to 'src/librustc_parse/parser') diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 23d2858a499..7dbd2362f04 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -616,7 +616,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { unsafety, polarity, defaultness: _, - constness: _, // TODO + constness: _, generics: _, of_trait: Some(_), ref self_ty, @@ -650,7 +650,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { unsafety, polarity, defaultness, - constness: _, // TODO + constness, generics: _, of_trait: None, self_ty: _, @@ -678,6 +678,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .note("only trait implementations may be annotated with default") .emit(); } + if constness == Constness::Const { + self.err_handler() + .struct_span_err(item.span, "inherent impls cannot be `const`") + .note("only trait implementations may be annotated with `const`") + .emit(); + } } ItemKind::Fn(ref sig, ref generics, _) => { self.visit_fn_header(&sig.header); diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index e4982896376..43495da1928 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -5,7 +5,7 @@ use crate::maybe_whole; use rustc_error_codes::*; 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}; @@ -566,9 +566,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. @@ -631,8 +631,7 @@ 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, @@ -646,13 +645,6 @@ 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, -- cgit 1.4.1-3-g733a5 From eb60346cc99bde574708fe2e419898044868c1f8 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 13 Jan 2020 20:30:27 -0800 Subject: Add `MaybeConst` variant to `{ast,hir}::TraitBoundModifier` --- src/librustc_ast_lowering/lib.rs | 8 +++----- src/librustc_ast_passes/ast_validation.rs | 20 ++++--------------- src/librustc_hir/hir.rs | 1 + src/librustc_parse/parser/ty.rs | 33 ++++++++++++++++++++++--------- src/librustdoc/html/format.rs | 1 + src/libsyntax/ast.rs | 11 +++++++++-- 6 files changed, 42 insertions(+), 32 deletions(-) (limited to 'src/librustc_parse/parser') 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 { + 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. -- cgit 1.4.1-3-g733a5 From 0ac4ba0eed776599e2d9f2ef76f6ae94a4471a4e Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 20 Jan 2020 01:20:45 -0800 Subject: Parse `?const ?Trait` --- src/librustc_ast_lowering/lib.rs | 9 +++++++-- src/librustc_ast_passes/ast_validation.rs | 17 +++++++++++++---- src/librustc_parse/parser/ty.rs | 23 +++++------------------ src/libsyntax/ast.rs | 5 +++++ 4 files changed, 30 insertions(+), 24 deletions(-) (limited to 'src/librustc_parse/parser') diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 90560c371e2..bc922fa0f55 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -1254,7 +1254,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | GenericBound::Trait(ref ty, TraitBoundModifier::MaybeConst) => { Some(this.lower_poly_trait_ref(ty, itctx.reborrow())) } - GenericBound::Trait(_, TraitBoundModifier::Maybe) => None, + GenericBound::Trait(_, TraitBoundModifier::Maybe) + | GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => { + None + } GenericBound::Outlives(ref lifetime) => { if lifetime_bound.is_none() { lifetime_bound = Some(this.lower_lifetime(lifetime)); @@ -2297,8 +2300,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_trait_bound_modifier(&mut self, f: TraitBoundModifier) -> hir::TraitBoundModifier { match f { TraitBoundModifier::None => hir::TraitBoundModifier::None, - TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe, TraitBoundModifier::MaybeConst => hir::TraitBoundModifier::MaybeConst, + TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => { + hir::TraitBoundModifier::Maybe + } } } diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 23cb9734833..9b71704f52d 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -917,11 +917,20 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } fn visit_param_bound(&mut self, bound: &'a GenericBound) { - 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); + match bound { + GenericBound::Trait(_, TraitBoundModifier::MaybeConst) => { + 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); + } + } + + GenericBound::Trait(_, TraitBoundModifier::MaybeConstMaybe) => { + self.err_handler() + .span_err(bound.span(), "`?const` and `?` are mutually exclusive"); } + + _ => {} } visit::walk_param_bound(self, bound) diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 9c9180778e5..efd8acc933a 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -27,17 +27,13 @@ struct BoundModifiers { } impl BoundModifiers { - fn to_trait_bound_modifier(&self) -> Result { - let modifier = match (self.maybe, self.maybe_const) { + 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(_)) => { - return Err("`?const` and `?` are mutually exclusive"); - } - }; - - Ok(modifier) + (Some(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe, + } } } @@ -563,16 +559,7 @@ impl<'a> Parser<'a> { self.expect(&token::CloseDelim(token::Paren))?; } - 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 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)) } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 88bfb8ccb95..5f38ac4cc0f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -279,6 +279,11 @@ pub enum TraitBoundModifier { /// `?const Trait` MaybeConst, + + /// `?const ?Trait` + // + // This parses but will be rejected during AST validation. + MaybeConstMaybe, } /// The AST represents all type param bounds as types. -- cgit 1.4.1-3-g733a5