about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-02-15 02:23:10 +0100
committerMazdak Farrokhzad <twingoow@gmail.com>2020-02-15 20:57:12 +0100
commit35884fe16889b39d4be43cf8effc3bdf843c6f12 (patch)
treec9d96a9b030337918d88626ee48bb3c7bebb3060
parentf8d2264463162291f5cb3391c98d7bc95ec17d87 (diff)
downloadrust-35884fe16889b39d4be43cf8effc3bdf843c6f12.tar.gz
rust-35884fe16889b39d4be43cf8effc3bdf843c6f12.zip
parse extern consts
-rw-r--r--src/librustc_ast_lowering/item.rs5
-rw-r--r--src/librustc_ast_passes/ast_validation.rs17
-rw-r--r--src/librustc_ast_passes/feature_gate.rs2
-rw-r--r--src/librustc_ast_pretty/pprust.rs3
-rw-r--r--src/librustc_parse/parser/item.rs27
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs2
-rw-r--r--src/librustc_resolve/late.rs2
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs2
-rw-r--r--src/librustc_save_analysis/lib.rs2
-rw-r--r--src/librustc_save_analysis/sig.rs1
-rw-r--r--src/libsyntax/ast.rs4
-rw-r--r--src/libsyntax/mut_visit.rs2
-rw-r--r--src/libsyntax/visit.rs3
-rw-r--r--src/test/ui/extern/extern-const.stderr10
-rw-r--r--src/test/ui/parser/foreign-const-semantic-fail.rs8
-rw-r--r--src/test/ui/parser/foreign-const-semantic-fail.stderr27
-rw-r--r--src/test/ui/parser/foreign-const-syntactic-pass.rs11
-rw-r--r--src/test/ui/parser/removed-syntax-extern-const.rs6
-rw-r--r--src/test/ui/parser/removed-syntax-extern-const.stderr8
19 files changed, 98 insertions, 44 deletions
diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs
index b465fd79c8f..e0db8606bc2 100644
--- a/src/librustc_ast_lowering/item.rs
+++ b/src/librustc_ast_lowering/item.rs
@@ -683,6 +683,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     let ty = self.lower_ty(t, ImplTraitContext::disallowed());
                     hir::ForeignItemKind::Static(ty, m)
                 }
+                ForeignItemKind::Const(ref t, _) => {
+                    // For recovery purposes.
+                    let ty = self.lower_ty(t, ImplTraitContext::disallowed());
+                    hir::ForeignItemKind::Static(ty, Mutability::Not)
+                }
                 ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type,
                 ForeignItemKind::Macro(_) => panic!("macro shouldn't exist here"),
             },
diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs
index 72cffdd750a..8efd50ad098 100644
--- a/src/librustc_ast_passes/ast_validation.rs
+++ b/src/librustc_ast_passes/ast_validation.rs
@@ -533,6 +533,20 @@ impl<'a> AstValidator<'a> {
         }
     }
 
+    fn error_foreign_const(&self, ident: Ident, span: Span) {
+        self.err_handler()
+            .struct_span_err(ident.span, "extern items cannot be `const`")
+            .span_suggestion(
+                span.with_hi(ident.span.lo()),
+                "try using a static value",
+                "static ".to_string(),
+                Applicability::MachineApplicable,
+            )
+            .span_label(self.current_extern_span(), "in this `extern` block")
+            .note(MORE_EXTERN)
+            .emit();
+    }
+
     /// Reject C-varadic type unless the function is foreign,
     /// or free and `unsafe extern "C"` semantically.
     fn check_c_varadic_type(&self, fk: FnKind<'a>) {
@@ -989,6 +1003,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             ForeignItemKind::Static(_, _, body) => {
                 self.check_foreign_kind_bodyless(fi.ident, "static", body.as_ref().map(|b| b.span));
             }
+            ForeignItemKind::Const(..) => {
+                self.error_foreign_const(fi.ident, fi.span);
+            }
             ForeignItemKind::Macro(..) => {}
         }
 
diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs
index c543f7095b9..d4de2c93758 100644
--- a/src/librustc_ast_passes/feature_gate.rs
+++ b/src/librustc_ast_passes/feature_gate.rs
@@ -400,7 +400,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
             ast::ForeignItemKind::TyAlias(..) => {
                 gate_feature_post!(&self, extern_types, i.span, "extern types are experimental");
             }
-            ast::ForeignItemKind::Macro(..) => {}
+            ast::ForeignItemKind::Macro(..) | ast::ForeignItemKind::Const(..) => {}
         }
 
         visit::walk_foreign_item(self, i)
diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs
index ee1a829da1a..410600e4957 100644
--- a/src/librustc_ast_pretty/pprust.rs
+++ b/src/librustc_ast_pretty/pprust.rs
@@ -1023,6 +1023,9 @@ impl<'a> State<'a> {
             ast::ForeignItemKind::Fn(sig, gen, body) => {
                 self.print_fn_full(sig, item.ident, gen, &item.vis, body.as_deref(), &item.attrs);
             }
+            ast::ForeignItemKind::Const(ty, body) => {
+                self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis);
+            }
             ast::ForeignItemKind::Static(ty, mutbl, body) => {
                 self.print_item_const(item.ident, Some(*mutbl), ty, body.as_deref(), &item.vis);
             }
diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs
index 9b7728f27d0..5fcd72090ec 100644
--- a/src/librustc_parse/parser/item.rs
+++ b/src/librustc_parse/parser/item.rs
@@ -880,19 +880,12 @@ impl<'a> Parser<'a> {
         } else if self.is_static_global() {
             // FOREIGN STATIC ITEM
             self.bump(); // `static`
-            self.parse_item_foreign_static()?
-        } else if self.token.is_keyword(kw::Const) {
-            // Treat `const` as `static` for error recovery, but don't add it to expected tokens.
-            self.bump(); // `const`
-            self.struct_span_err(self.prev_span, "extern items cannot be `const`")
-                .span_suggestion(
-                    self.prev_span,
-                    "try using a static value",
-                    "static".to_owned(),
-                    Applicability::MachineApplicable,
-                )
-                .emit();
-            self.parse_item_foreign_static()?
+            let mutbl = self.parse_mutability();
+            let (ident, ty, expr) = self.parse_item_const_common(Some(mutbl))?;
+            (ident, ForeignItemKind::Static(ty, mutbl, expr))
+        } else if self.eat_keyword(kw::Const) {
+            let (ident, ty, expr) = self.parse_item_const_common(None)?;
+            (ident, ForeignItemKind::Const(ty, expr))
         } else if self.isnt_macro_invocation() {
             return Err(self.missing_assoc_item_kind_err("extern", self.prev_span));
         } else if self.token.is_path_start() {
@@ -906,14 +899,6 @@ impl<'a> Parser<'a> {
         Ok(P(self.mk_item(lo, ident, kind, vis, attrs)))
     }
 
-    /// Parses a static item from a foreign module.
-    /// Assumes that the `static` keyword is already parsed.
-    fn parse_item_foreign_static(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> {
-        let mutbl = self.parse_mutability();
-        let (ident, ty, expr) = self.parse_item_const_common(Some(mutbl))?;
-        Ok((ident, ForeignItemKind::Static(ty, mutbl, expr)))
-    }
-
     /// Parses a type from a foreign module.
     fn parse_item_foreign_type(&mut self) -> PResult<'a, (Ident, ForeignItemKind)> {
         let (ident, kind) = self.parse_assoc_ty()?;
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 7c541928e6f..1f622b80e8e 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -826,7 +826,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
             ForeignItemKind::Fn(..) => {
                 (Res::Def(DefKind::Fn, self.r.definitions.local_def_id(item.id)), ValueNS)
             }
-            ForeignItemKind::Static(..) => {
+            ForeignItemKind::Static(..) | ForeignItemKind::Const(..) => {
                 (Res::Def(DefKind::Static, self.r.definitions.local_def_id(item.id)), ValueNS)
             }
             ForeignItemKind::TyAlias(..) => {
diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs
index 7b445fcc035..68559c0446a 100644
--- a/src/librustc_resolve/late.rs
+++ b/src/librustc_resolve/late.rs
@@ -443,7 +443,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                     visit::walk_foreign_item(this, foreign_item);
                 });
             }
-            ForeignItemKind::Static(..) => {
+            ForeignItemKind::Const(..) | ForeignItemKind::Static(..) => {
                 self.with_item_rib(HasGenericParams::No, |this| {
                     visit::walk_foreign_item(this, foreign_item);
                 });
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 001f2f09854..6a3abf4fbf5 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -1534,7 +1534,7 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> {
                     self.visit_ty(&ret_ty);
                 }
             }
-            ast::ForeignItemKind::Static(ref ty, _, _) => {
+            ast::ForeignItemKind::Const(ref ty, _) | ast::ForeignItemKind::Static(ref ty, _, _) => {
                 if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
                     down_cast_data!(var_data, DefData, item.span);
                     self.dumper.dump_def(&access, var_data);
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 6bb2bf4c1e9..d244370ae2c 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -151,7 +151,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> {
                     attributes: lower_attributes(item.attrs.clone(), self),
                 }))
             }
-            ast::ForeignItemKind::Static(ref ty, _, _) => {
+            ast::ForeignItemKind::Const(ref ty, _) | ast::ForeignItemKind::Static(ref ty, _, _) => {
                 filter!(self.span_utils, item.ident.span);
 
                 let id = id_from_node_id(item.id, self);
diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs
index 8fba3109f21..3c68124ad40 100644
--- a/src/librustc_save_analysis/sig.rs
+++ b/src/librustc_save_analysis/sig.rs
@@ -792,6 +792,7 @@ impl Sig for ast::ForeignItem {
 
                 Ok(Signature { text: text, defs: defs, refs: vec![] })
             }
+            ast::ForeignItemKind::Const(..) => Err("foreign const"),
             ast::ForeignItemKind::Macro(..) => Err("macro"),
         }
     }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index ca39fbd6c5d..5041d43b16c 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -2605,6 +2605,9 @@ pub type ForeignItem = Item<ForeignItemKind>;
 /// An item within an `extern` block.
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub enum ForeignItemKind {
+    /// A constant, `const $ident: $ty $def?;` where `def ::= "=" $expr? ;`.
+    /// If `def` is parsed, then the constant is provided, and otherwise required.
+    Const(P<Ty>, Option<P<Expr>>),
     /// A static item (`static FOO: u8`).
     Static(P<Ty>, Mutability, Option<P<Expr>>),
     /// A function.
@@ -2619,6 +2622,7 @@ impl ForeignItemKind {
     pub fn descriptive_variant(&self) -> &str {
         match *self {
             ForeignItemKind::Fn(..) => "foreign function",
+            ForeignItemKind::Const(..) => "foreign const item",
             ForeignItemKind::Static(..) => "foreign static item",
             ForeignItemKind::TyAlias(..) => "foreign type",
             ForeignItemKind::Macro(..) => "macro in foreign module",
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index 91db6158689..ffc42340dba 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -1046,7 +1046,7 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>(
             visitor.visit_generics(generics);
             visit_opt(body, |body| visitor.visit_block(body));
         }
-        ForeignItemKind::Static(ty, _, body) => {
+        ForeignItemKind::Const(ty, body) | ForeignItemKind::Static(ty, _, body) => {
             visitor.visit_ty(ty);
             visit_opt(body, |body| visitor.visit_expr(body));
         }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index f5763ecf573..5a21eb55528 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -534,7 +534,8 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI
             let kind = FnKind::Fn(FnCtxt::Foreign, item.ident, sig, &item.vis, body.as_deref());
             visitor.visit_fn(kind, item.span, item.id);
         }
-        ForeignItemKind::Static(ref typ, _, ref body) => {
+        ForeignItemKind::Const(ref typ, ref body)
+        | ForeignItemKind::Static(ref typ, _, ref body) => {
             visitor.visit_ty(typ);
             walk_list!(visitor, visit_expr, body);
         }
diff --git a/src/test/ui/extern/extern-const.stderr b/src/test/ui/extern/extern-const.stderr
index 258202b6903..97e11381c6f 100644
--- a/src/test/ui/extern/extern-const.stderr
+++ b/src/test/ui/extern/extern-const.stderr
@@ -1,8 +1,14 @@
 error: extern items cannot be `const`
-  --> $DIR/extern-const.rs:16:5
+  --> $DIR/extern-const.rs:16:11
    |
+LL | extern "C" {
+   | ---------- in this `extern` block
 LL |     const rust_dbg_static_mut: libc::c_int;
-   |     ^^^^^ help: try using a static value: `static`
+   |     ------^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     help: try using a static value: `static`
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/foreign-const-semantic-fail.rs b/src/test/ui/parser/foreign-const-semantic-fail.rs
new file mode 100644
index 00000000000..d28b6414282
--- /dev/null
+++ b/src/test/ui/parser/foreign-const-semantic-fail.rs
@@ -0,0 +1,8 @@
+fn main() {}
+
+extern {
+    const A: isize;
+    //~^ ERROR extern items cannot be `const`
+    const B: isize = 42;
+    //~^ ERROR extern items cannot be `const`
+}
diff --git a/src/test/ui/parser/foreign-const-semantic-fail.stderr b/src/test/ui/parser/foreign-const-semantic-fail.stderr
new file mode 100644
index 00000000000..799a795c593
--- /dev/null
+++ b/src/test/ui/parser/foreign-const-semantic-fail.stderr
@@ -0,0 +1,27 @@
+error: extern items cannot be `const`
+  --> $DIR/foreign-const-semantic-fail.rs:4:11
+   |
+LL | extern {
+   | ------ in this `extern` block
+LL |     const A: isize;
+   |     ------^
+   |     |
+   |     help: try using a static value: `static`
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: extern items cannot be `const`
+  --> $DIR/foreign-const-semantic-fail.rs:6:11
+   |
+LL | extern {
+   | ------ in this `extern` block
+...
+LL |     const B: isize = 42;
+   |     ------^
+   |     |
+   |     help: try using a static value: `static`
+   |
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/parser/foreign-const-syntactic-pass.rs b/src/test/ui/parser/foreign-const-syntactic-pass.rs
new file mode 100644
index 00000000000..bacef8e71d6
--- /dev/null
+++ b/src/test/ui/parser/foreign-const-syntactic-pass.rs
@@ -0,0 +1,11 @@
+// Syntactically, a `const` item inside an `extern { ... }` block is allowed.
+
+// check-pass
+
+fn main() {}
+
+#[cfg(FALSE)]
+extern {
+    const A: isize;
+    const B: isize = 42;
+}
diff --git a/src/test/ui/parser/removed-syntax-extern-const.rs b/src/test/ui/parser/removed-syntax-extern-const.rs
deleted file mode 100644
index 71c22e62f8e..00000000000
--- a/src/test/ui/parser/removed-syntax-extern-const.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-extern {
-    const i: isize;
-    //~^ ERROR extern items cannot be `const`
-}
-
-fn main() {}
diff --git a/src/test/ui/parser/removed-syntax-extern-const.stderr b/src/test/ui/parser/removed-syntax-extern-const.stderr
deleted file mode 100644
index 2bccbd91452..00000000000
--- a/src/test/ui/parser/removed-syntax-extern-const.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: extern items cannot be `const`
-  --> $DIR/removed-syntax-extern-const.rs:2:5
-   |
-LL |     const i: isize;
-   |     ^^^^^ help: try using a static value: `static`
-
-error: aborting due to previous error
-