diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2020-02-14 14:21:02 +0100 |
|---|---|---|
| committer | Mazdak Farrokhzad <twingoow@gmail.com> | 2020-02-15 20:57:12 +0100 |
| commit | f3e9763543e5828fe9eee7f5e78c88193f5b8ba5 (patch) | |
| tree | 4d61cb1d454b4951c452ce9008832147992e57d7 /src | |
| parent | 95dc9b9a73353a786e3c934c5074fb793ff7a735 (diff) | |
| download | rust-f3e9763543e5828fe9eee7f5e78c88193f5b8ba5.tar.gz rust-f3e9763543e5828fe9eee7f5e78c88193f5b8ba5.zip | |
ast: make `= <expr>;` optional in free statics/consts.
Diffstat (limited to 'src')
19 files changed, 250 insertions, 132 deletions
diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 6c4026408ed..f19481d890d 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -269,26 +269,12 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_use_tree(use_tree, &prefix, id, vis, ident, attrs) } ItemKind::Static(ref t, m, ref e) => { - let ty = self.lower_ty( - t, - if self.sess.features_untracked().impl_trait_in_bindings { - ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc) - } else { - ImplTraitContext::Disallowed(ImplTraitPosition::Binding) - }, - ); - hir::ItemKind::Static(ty, m, self.lower_const_body(span, Some(e))) + let (ty, body_id) = self.lower_const_item(t, span, e.as_deref()); + hir::ItemKind::Static(ty, m, body_id) } ItemKind::Const(ref t, ref e) => { - let ty = self.lower_ty( - t, - if self.sess.features_untracked().impl_trait_in_bindings { - ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc) - } else { - ImplTraitContext::Disallowed(ImplTraitPosition::Binding) - }, - ); - hir::ItemKind::Const(ty, self.lower_const_body(span, Some(e))) + let (ty, body_id) = self.lower_const_item(t, span, e.as_deref()); + hir::ItemKind::Const(ty, body_id) } ItemKind::Fn(FnSig { ref decl, header }, ref generics, ref body) => { let fn_def_id = self.resolver.definitions().local_def_id(id); @@ -457,6 +443,21 @@ impl<'hir> LoweringContext<'_, 'hir> { // not cause an assertion failure inside the `lower_defaultness` function. } + fn lower_const_item( + &mut self, + ty: &Ty, + span: Span, + body: Option<&Expr>, + ) -> (&'hir hir::Ty<'hir>, hir::BodyId) { + let itctx = if self.sess.features_untracked().impl_trait_in_bindings { + ImplTraitContext::OpaqueTy(None, hir::OpaqueTyOrigin::Misc) + } else { + ImplTraitContext::Disallowed(ImplTraitPosition::Binding) + }; + let ty = self.lower_ty(ty, itctx); + (ty, self.lower_const_body(span, body)) + } + fn lower_use_tree( &mut self, tree: &UseTree, diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index c539f98aecf..fdbf866cd9a 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -948,6 +948,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.err_handler().span_err(item.span, "unions cannot have zero fields"); } } + ItemKind::Const(.., None) => { + let msg = "free constant item without body"; + self.error_item_without_body(item.span, "constant", msg, " = <expr>;"); + } + ItemKind::Static(.., None) => { + let msg = "free static item without body"; + self.error_item_without_body(item.span, "static", msg, " = <expr>;"); + } _ => {} } diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index b0e1b5d4f42..356fdd1e71c 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -1124,9 +1124,10 @@ impl<'a> State<'a> { self.print_type(ty); self.s.space(); self.end(); // end the head-ibox - - self.word_space("="); - self.print_expr(expr); + if let Some(expr) = expr { + self.word_space("="); + self.print_expr(expr); + } self.s.word(";"); self.end(); // end the outer cbox } @@ -1137,9 +1138,10 @@ impl<'a> State<'a> { self.print_type(ty); self.s.space(); self.end(); // end the head-ibox - - self.word_space("="); - self.print_expr(expr); + if let Some(expr) = expr { + self.word_space("="); + self.print_expr(expr); + } self.s.word(";"); self.end(); // end the outer cbox } diff --git a/src/librustc_builtin_macros/test.rs b/src/librustc_builtin_macros/test.rs index 02a0bc00c11..b6837c0703a 100644 --- a/src/librustc_builtin_macros/test.rs +++ b/src/librustc_builtin_macros/test.rs @@ -186,81 +186,85 @@ pub fn expand_test_or_bench( ast::ItemKind::Const( cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))), // test::TestDescAndFn { - cx.expr_struct( - sp, - test_path("TestDescAndFn"), - vec![ - // desc: test::TestDesc { - field( - "desc", - cx.expr_struct( - sp, - test_path("TestDesc"), - vec![ - // name: "path::to::test" - field( - "name", - cx.expr_call( - sp, - cx.expr_path(test_path("StaticTestName")), - vec![cx.expr_str( - sp, - Symbol::intern(&item_path( - // skip the name of the root module - &cx.current_expansion.module.mod_path[1..], - &item.ident, - )), - )], - ), - ), - // ignore: true | false - field("ignore", cx.expr_bool(sp, should_ignore(&item))), - // allow_fail: true | false - field("allow_fail", cx.expr_bool(sp, should_fail(&item))), - // should_panic: ... - field( - "should_panic", - match should_panic(cx, &item) { - // test::ShouldPanic::No - ShouldPanic::No => cx.expr_path(should_panic_path("No")), - // test::ShouldPanic::Yes - ShouldPanic::Yes(None) => { - cx.expr_path(should_panic_path("Yes")) - } - // test::ShouldPanic::YesWithMessage("...") - ShouldPanic::Yes(Some(sym)) => cx.expr_call( + Some( + cx.expr_struct( + sp, + test_path("TestDescAndFn"), + vec![ + // desc: test::TestDesc { + field( + "desc", + cx.expr_struct( + sp, + test_path("TestDesc"), + vec![ + // name: "path::to::test" + field( + "name", + cx.expr_call( sp, - cx.expr_path(should_panic_path("YesWithMessage")), - vec![cx.expr_str(sp, sym)], + cx.expr_path(test_path("StaticTestName")), + vec![cx.expr_str( + sp, + Symbol::intern(&item_path( + // skip the name of the root module + &cx.current_expansion.module.mod_path[1..], + &item.ident, + )), + )], ), - }, - ), - // test_type: ... - field( - "test_type", - match test_type(cx) { - // test::TestType::UnitTest - TestType::UnitTest => { - cx.expr_path(test_type_path("UnitTest")) - } - // test::TestType::IntegrationTest - TestType::IntegrationTest => { - cx.expr_path(test_type_path("IntegrationTest")) - } - // test::TestPath::Unknown - TestType::Unknown => { - cx.expr_path(test_type_path("Unknown")) - } - }, - ), - // }, - ], + ), + // ignore: true | false + field("ignore", cx.expr_bool(sp, should_ignore(&item))), + // allow_fail: true | false + field("allow_fail", cx.expr_bool(sp, should_fail(&item))), + // should_panic: ... + field( + "should_panic", + match should_panic(cx, &item) { + // test::ShouldPanic::No + ShouldPanic::No => { + cx.expr_path(should_panic_path("No")) + } + // test::ShouldPanic::Yes + ShouldPanic::Yes(None) => { + cx.expr_path(should_panic_path("Yes")) + } + // test::ShouldPanic::YesWithMessage("...") + ShouldPanic::Yes(Some(sym)) => cx.expr_call( + sp, + cx.expr_path(should_panic_path("YesWithMessage")), + vec![cx.expr_str(sp, sym)], + ), + }, + ), + // test_type: ... + field( + "test_type", + match test_type(cx) { + // test::TestType::UnitTest + TestType::UnitTest => { + cx.expr_path(test_type_path("UnitTest")) + } + // test::TestType::IntegrationTest + TestType::IntegrationTest => { + cx.expr_path(test_type_path("IntegrationTest")) + } + // test::TestPath::Unknown + TestType::Unknown => { + cx.expr_path(test_type_path("Unknown")) + } + }, + ), + // }, + ], + ), ), - ), - // testfn: test::StaticTestFn(...) | test::StaticBenchFn(...) - field("testfn", test_fn), // } - ], - ), // } + // testfn: test::StaticTestFn(...) | test::StaticBenchFn(...) + field("testfn", test_fn), // } + ], + ), // } + ), ), ); test_const = test_const.map(|mut tc| { diff --git a/src/librustc_expand/build.rs b/src/librustc_expand/build.rs index af22e46eb6a..08821510630 100644 --- a/src/librustc_expand/build.rs +++ b/src/librustc_expand/build.rs @@ -634,7 +634,7 @@ impl<'a> ExtCtxt<'a> { mutbl: ast::Mutability, expr: P<ast::Expr>, ) -> P<ast::Item> { - self.item(span, name, Vec::new(), ast::ItemKind::Static(ty, mutbl, expr)) + self.item(span, name, Vec::new(), ast::ItemKind::Static(ty, mutbl, Some(expr))) } pub fn item_const( @@ -644,7 +644,7 @@ impl<'a> ExtCtxt<'a> { ty: P<ast::Ty>, expr: P<ast::Expr>, ) -> P<ast::Item> { - self.item(span, name, Vec::new(), ast::ItemKind::Const(ty, expr)) + self.item(span, name, Vec::new(), ast::ItemKind::Const(ty, Some(expr))) } pub fn attribute(&self, mi: ast::MetaItem) -> ast::Attribute { diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 480df99a01e..7870b9da4cb 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -603,7 +603,7 @@ impl EarlyLintPass for UnusedParens { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { use ast::ItemKind::*; - if let Const(.., ref expr) | Static(.., ref expr) = item.kind { + if let Const(.., Some(expr)) | Static(.., Some(expr)) = &item.kind { self.check_unused_parens_expr(cx, expr, "assigned value", false, None, None); } } diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 4a5b4ff8e04..893cbf5adfa 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -966,7 +966,7 @@ impl<'a> Parser<'a> { } } - /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty = $expr` with + /// Parse `["const" | ("static" "mut"?)] $ident ":" $ty (= $expr)?` with /// `["const" | ("static" "mut"?)]` already parsed and stored in `m`. /// /// When `m` is `"const"`, `$ident` may also be `"_"`. @@ -975,25 +975,22 @@ impl<'a> Parser<'a> { // Parse the type of a `const` or `static mut?` item. // That is, the `":" $ty` fragment. - let ty = if self.token == token::Eq { - self.recover_missing_const_type(id, m) - } else { - // Not `=` so expect `":"" $ty` as usual. - self.expect(&token::Colon)?; + let ty = if self.eat(&token::Colon) { self.parse_ty()? + } else { + self.recover_missing_const_type(id, m) }; - self.expect(&token::Eq)?; - let e = self.parse_expr()?; + let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None }; self.expect_semi()?; let item = match m { - Some(m) => ItemKind::Static(ty, m, e), - None => ItemKind::Const(ty, e), + Some(m) => ItemKind::Static(ty, m, expr), + None => ItemKind::Const(ty, expr), }; Ok((id, item)) } - /// We were supposed to parse `:` but instead, we're already at `=`. + /// We were supposed to parse `:` but the `:` was missing. /// This means that the type is missing. fn recover_missing_const_type(&mut self, id: Ident, m: Option<Mutability>) -> P<Ty> { // Construct the error and stash it away with the hope diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 1a1a9b1076e..36667e1d6ff 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -881,9 +881,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { debug!("resolve_item ItemKind::Const"); self.with_item_rib(HasGenericParams::No, |this| { this.visit_ty(ty); - this.with_constant_rib(|this| { - this.visit_expr(expr); - }); + if let Some(expr) = expr { + this.with_constant_rib(|this| this.visit_expr(expr)); + } }); } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 5668be40eef..fc5496eb182 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -400,7 +400,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { &mut self, item: &'l ast::Item, typ: &'l ast::Ty, - expr: &'l ast::Expr, + expr: Option<&'l ast::Expr>, ) { let hir_id = self.tcx.hir().node_to_hir_id(item.id); self.nest_tables(item.id, |v| { @@ -409,7 +409,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { v.dumper.dump_def(&access_from!(v.save_ctxt, item, hir_id), var_data); } v.visit_ty(&typ); - v.visit_expr(expr); + walk_list!(v, visit_expr, expr); }); } @@ -1293,8 +1293,8 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> { Fn(ref sig, ref ty_params, ref body) => { self.process_fn(item, &sig.decl, &sig.header, ty_params, body.as_deref()) } - Static(ref typ, _, ref expr) => self.process_static_or_const_item(item, typ, expr), - Const(ref typ, ref expr) => self.process_static_or_const_item(item, &typ, &expr), + Static(ref typ, _, ref e) => self.process_static_or_const_item(item, typ, e.as_deref()), + Const(ref typ, ref e) => self.process_static_or_const_item(item, typ, e.as_deref()), Struct(ref def, ref ty_params) | Union(ref def, ref ty_params) => { self.process_struct(item, def, ty_params) } diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index bd7bd9bc616..d678a8b067e 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -334,10 +334,13 @@ impl Sig for ast::Item { let ty = ty.make(offset + text.len(), id, scx)?; text.push_str(&ty.text); - text.push_str(" = "); - let expr = pprust::expr_to_string(expr).replace('\n', " "); - text.push_str(&expr); + if let Some(expr) = expr { + text.push_str(" = "); + let expr = pprust::expr_to_string(expr).replace('\n', " "); + text.push_str(&expr); + } + text.push(';'); Ok(extend_sig(ty, text, defs, vec![])) @@ -355,10 +358,13 @@ impl Sig for ast::Item { let ty = ty.make(offset + text.len(), id, scx)?; text.push_str(&ty.text); - text.push_str(" = "); - let expr = pprust::expr_to_string(expr).replace('\n', " "); - text.push_str(&expr); + if let Some(expr) = expr { + text.push_str(" = "); + let expr = pprust::expr_to_string(expr).replace('\n', " "); + text.push_str(&expr); + } + text.push(';'); Ok(extend_sig(ty, text, defs, vec![])) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index fe353bc994a..61ae14cae02 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2496,11 +2496,11 @@ pub enum ItemKind { /// A static item (`static`). /// /// E.g., `static FOO: i32 = 42;` or `static FOO: &'static str = "bar";`. - Static(P<Ty>, Mutability, P<Expr>), + Static(P<Ty>, Mutability, Option<P<Expr>>), /// A constant item (`const`). /// /// E.g., `const FOO: i32 = 42;`. - Const(P<Ty>, P<Expr>), + Const(P<Ty>, Option<P<Expr>>), /// A function declaration (`fn`). /// /// E.g., `fn foo(bar: usize) -> usize { .. }`. diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index d36b0a28a8c..cd7a3becca7 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -890,13 +890,9 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) { match kind { ItemKind::ExternCrate(_orig_name) => {} ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), - ItemKind::Static(ty, _mut, expr) => { + ItemKind::Static(ty, _, expr) | ItemKind::Const(ty, expr) => { vis.visit_ty(ty); - vis.visit_expr(expr); - } - ItemKind::Const(ty, expr) => { - vis.visit_ty(ty); - vis.visit_expr(expr); + visit_opt(expr, |expr| vis.visit_expr(expr)); } ItemKind::Fn(sig, generics, body) => { visit_fn_sig(sig, vis); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index ed57fc8abf3..4beb94e9f0c 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -300,7 +300,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { ItemKind::Use(ref use_tree) => visitor.visit_use_tree(use_tree, item.id, false), ItemKind::Static(ref typ, _, ref expr) | ItemKind::Const(ref typ, ref expr) => { visitor.visit_ty(typ); - visitor.visit_expr(expr); + walk_list!(visitor, visit_expr, expr); } ItemKind::Fn(ref sig, ref generics, ref body) => { visitor.visit_generics(generics); diff --git a/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs b/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs new file mode 100644 index 00000000000..613b3c98561 --- /dev/null +++ b/src/test/ui/parser/item-free-const-no-body-semantic-fail.rs @@ -0,0 +1,7 @@ +// Semantically, a free `const` item cannot omit its body. + +fn main() {} + +const A: u8; //~ ERROR free constant item without body +const B; //~ ERROR free constant item without body +//~^ ERROR missing type for `const` item diff --git a/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr b/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr new file mode 100644 index 00000000000..4e97229fa1a --- /dev/null +++ b/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr @@ -0,0 +1,24 @@ +error: free constant item without body + --> $DIR/item-free-const-no-body-semantic-fail.rs:5:1 + | +LL | const A: u8; + | ^^^^^^^^^^^- + | | + | help: provide a definition for the constant: `= <expr>;` + +error: free constant item without body + --> $DIR/item-free-const-no-body-semantic-fail.rs:6:1 + | +LL | const B; + | ^^^^^^^- + | | + | help: provide a definition for the constant: `= <expr>;` + +error: missing type for `const` item + --> $DIR/item-free-const-no-body-semantic-fail.rs:6:7 + | +LL | const B; + | ^ help: provide a type for the item: `B: [type error]` + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/parser/item-free-const-no-body-syntactic-pass.rs b/src/test/ui/parser/item-free-const-no-body-syntactic-pass.rs new file mode 100644 index 00000000000..acfdd3c363f --- /dev/null +++ b/src/test/ui/parser/item-free-const-no-body-syntactic-pass.rs @@ -0,0 +1,8 @@ +// Syntactically, a free `const` item can omit its body. + +// check-pass + +fn main() {} + +#[cfg(FALSE)] +const X: u8; diff --git a/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs b/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs new file mode 100644 index 00000000000..780479e3d26 --- /dev/null +++ b/src/test/ui/parser/item-free-static-no-body-semantic-fail.rs @@ -0,0 +1,11 @@ +// Semantically, a free `static` item cannot omit its body. + +fn main() {} + +static A: u8; //~ ERROR free static item without body +static B; //~ ERROR free static item without body +//~^ ERROR missing type for `static` item + +static mut C: u8; //~ ERROR free static item without body +static mut D; //~ ERROR free static item without body +//~^ ERROR missing type for `static mut` item diff --git a/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr b/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr new file mode 100644 index 00000000000..60b7bb34c69 --- /dev/null +++ b/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr @@ -0,0 +1,46 @@ +error: free static item without body + --> $DIR/item-free-static-no-body-semantic-fail.rs:5:1 + | +LL | static A: u8; + | ^^^^^^^^^^^^- + | | + | help: provide a definition for the static: `= <expr>;` + +error: free static item without body + --> $DIR/item-free-static-no-body-semantic-fail.rs:6:1 + | +LL | static B; + | ^^^^^^^^- + | | + | help: provide a definition for the static: `= <expr>;` + +error: free static item without body + --> $DIR/item-free-static-no-body-semantic-fail.rs:9:1 + | +LL | static mut C: u8; + | ^^^^^^^^^^^^^^^^- + | | + | help: provide a definition for the static: `= <expr>;` + +error: free static item without body + --> $DIR/item-free-static-no-body-semantic-fail.rs:10:1 + | +LL | static mut D; + | ^^^^^^^^^^^^- + | | + | help: provide a definition for the static: `= <expr>;` + +error: missing type for `static` item + --> $DIR/item-free-static-no-body-semantic-fail.rs:6:8 + | +LL | static B; + | ^ help: provide a type for the item: `B: [type error]` + +error: missing type for `static mut` item + --> $DIR/item-free-static-no-body-semantic-fail.rs:10:12 + | +LL | static mut D; + | ^ help: provide a type for the item: `D: [type error]` + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/parser/item-free-static-no-body-syntactic-pass.rs b/src/test/ui/parser/item-free-static-no-body-syntactic-pass.rs new file mode 100644 index 00000000000..db0039204d8 --- /dev/null +++ b/src/test/ui/parser/item-free-static-no-body-syntactic-pass.rs @@ -0,0 +1,8 @@ +// Syntactically, a free `const` item can omit its body. + +// check-pass + +fn main() {} + +#[cfg(FALSE)] +static X: u8; |
