From 60dd83ea85853f6a31f8998eb80ce47446fdb785 Mon Sep 17 00:00:00 2001 From: Paul Woolcock Date: Wed, 24 May 2017 13:58:37 -0400 Subject: add `allow_fail` test attribute This change allows the user to add an `#[allow_fail]` attribute to tests that will cause the test to compile & run, but if the test fails it will not cause the entire test run to fail. The test output will show the failure, but in yellow instead of red, and also indicate that it was an allowed failure. --- src/libsyntax/feature_gate.rs | 1 + src/libsyntax/test.rs | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d7d3a70f3c7..07db5b83331 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -534,6 +534,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG ("derive", Normal, Ungated), ("should_panic", Normal, Ungated), ("ignore", Normal, Ungated), + ("allow_fail", Normal, Ungated), ("no_implicit_prelude", Normal, Ungated), ("reexport_test_harness_main", Normal, Ungated), ("link_args", Normal, Ungated), diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index a0d1785c6ff..86f5f42eac7 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -52,7 +52,8 @@ struct Test { path: Vec , bench: bool, ignore: bool, - should_panic: ShouldPanic + should_panic: ShouldPanic, + allow_fail: bool, } struct TestCtxt<'a> { @@ -133,7 +134,8 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { path: self.cx.path.clone(), bench: is_bench_fn(&self.cx, &i), ignore: is_ignored(&i), - should_panic: should_panic(&i, &self.cx) + should_panic: should_panic(&i, &self.cx), + allow_fail: is_allowed_fail(&i), }; self.cx.testfns.push(test); self.tests.push(i.ident); @@ -383,6 +385,10 @@ fn is_ignored(i: &ast::Item) -> bool { i.attrs.iter().any(|attr| attr.check_name("ignore")) } +fn is_allowed_fail(i: &ast::Item) -> bool { + i.attrs.iter().any(|attr| attr.check_name("allow_fail")) +} + fn should_panic(i: &ast::Item, cx: &TestCtxt) -> ShouldPanic { match i.attrs.iter().find(|attr| attr.check_name("should_panic")) { Some(attr) => { @@ -668,6 +674,7 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { } } }; + let allow_fail_expr = ecx.expr_bool(span, test.allow_fail); // self::test::TestDesc { ... } let desc_expr = ecx.expr_struct( @@ -675,7 +682,8 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P { test_path("TestDesc"), vec![field("name", name_expr), field("ignore", ignore_expr), - field("should_panic", fail_expr)]); + field("should_panic", fail_expr), + field("allow_fail", allow_fail_expr)]); let mut visible_path = match cx.toplevel_reexport { -- cgit 1.4.1-3-g733a5 From 8e5a3023c9ef299be6a617bca55ad16d12ce1036 Mon Sep 17 00:00:00 2001 From: Paul Woolcock Date: Fri, 23 Jun 2017 09:43:28 -0400 Subject: Add a feature gate for the `#[allow_fail]` attribute --- src/libsyntax/feature_gate.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/libsyntax') diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 07db5b83331..74bf19b841e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -354,6 +354,9 @@ declare_features! ( // rustc internal (active, abi_thiscall, "1.19.0", None), + + // Allows a test to fail without failing the whole suite + (active, allow_fail, "1.19.0", Some(42219)), ); declare_features! ( @@ -534,7 +537,6 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG ("derive", Normal, Ungated), ("should_panic", Normal, Ungated), ("ignore", Normal, Ungated), - ("allow_fail", Normal, Ungated), ("no_implicit_prelude", Normal, Ungated), ("reexport_test_harness_main", Normal, Ungated), ("link_args", Normal, Ungated), @@ -813,6 +815,11 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "used internally by rustc", cfg_fn!(rustc_attrs))), + ("allow_fail", Normal, Gated(Stability::Unstable, + "allow_fail", + "allow_fail attribute is currently unstable", + cfg_fn!(allow_fail))), + // Crate level attributes ("crate_name", CrateLevel, Ungated), ("crate_type", CrateLevel, Ungated), -- cgit 1.4.1-3-g733a5 From 0dfd9c30f2c61458343e0816c66f448019e826d1 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sat, 24 Jun 2017 18:26:04 +0000 Subject: syntax: allow negative integer literal expression to be interpolated as pattern --- src/librustc_lint/builtin.rs | 10 ++----- src/librustc_passes/ast_validation.rs | 26 ++++++++++++++++ src/libsyntax/parse/parser.rs | 4 ++- src/test/compile-fail/patkind-litrange-no-expr.rs | 36 +++++++++++++++++++++++ src/test/run-pass/macro-pat-neg-lit.rs | 35 ++++++++++++++++++++++ 5 files changed, 103 insertions(+), 8 deletions(-) create mode 100644 src/test/compile-fail/patkind-litrange-no-expr.rs create mode 100644 src/test/run-pass/macro-pat-neg-lit.rs (limited to 'src/libsyntax') diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 9800012917c..57843047f51 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -684,13 +684,9 @@ fn fl_lit_check_expr(cx: &EarlyContext, expr: &ast::Expr) { // These may occur in patterns // and can maybe contain float literals ExprKind::Unary(_, ref f) => fl_lit_check_expr(cx, f), - // These may occur in patterns - // and can't contain float literals - ExprKind::Path(..) => (), - // If something unhandled is encountered, we need to expand the - // search or ignore more ExprKinds. - _ => span_bug!(expr.span, "Unhandled expression {:?} in float lit pattern lint", - expr.node), + // Other kinds of exprs can't occur in patterns so we don't have to check them + // (ast_validation will emit an error if they occur) + _ => (), } } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 7c443a4ac75..6ad03186dc7 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -93,6 +93,17 @@ impl<'a> AstValidator<'a> { } } } + + /// matches '-' lit | lit (cf. parser::Parser::parse_pat_literal_maybe_minus) + fn check_expr_within_pat(&self, expr: &Expr) { + match expr.node { + ExprKind::Lit(..) | ExprKind::Path(..) => {} + ExprKind::Unary(UnOp::Neg, ref inner) + if match inner.node { ExprKind::Lit(_) => true, _ => false } => {} + _ => self.err_handler().span_err(expr.span, "arbitrary expressions aren't allowed \ + in patterns") + } + } } impl<'a> Visitor<'a> for AstValidator<'a> { @@ -308,6 +319,21 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } visit::walk_generics(self, g) } + + fn visit_pat(&mut self, pat: &'a Pat) { + match pat.node { + PatKind::Lit(ref expr) => { + self.check_expr_within_pat(expr); + } + PatKind::Range(ref start, ref end, _) => { + self.check_expr_within_pat(start); + self.check_expr_within_pat(end); + } + _ => {} + } + + visit::walk_pat(self, pat) + } } pub fn check_crate(session: &Session, krate: &Crate) { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 851a638e148..5b0031b2f17 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1659,8 +1659,10 @@ impl<'a> Parser<'a> { Ok(codemap::Spanned { node: lit, span: lo.to(self.prev_span) }) } - /// matches '-' lit | lit + /// matches '-' lit | lit (cf. ast_validation::AstValidator::check_expr_within_pat) pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult<'a, P> { + maybe_whole_expr!(self); + let minus_lo = self.span; let minus_present = self.eat(&token::BinOp(token::Minus)); let lo = self.span; diff --git a/src/test/compile-fail/patkind-litrange-no-expr.rs b/src/test/compile-fail/patkind-litrange-no-expr.rs new file mode 100644 index 00000000000..afb2cbb7db3 --- /dev/null +++ b/src/test/compile-fail/patkind-litrange-no-expr.rs @@ -0,0 +1,36 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! enum_number { + ($name:ident { $($variant:ident = $value:expr, )* }) => { + enum $name { + $($variant = $value,)* + } + + fn foo(value: i32) -> Option<$name> { + match value { + $( $value => Some($name::$variant), )* // PatKind::Lit + $( $value ... 42 => Some($name::$variant), )* // PatKind::Range + _ => None + } + } + } +} + +enum_number!(Change { + Pos = 1, + Neg = -1, + Arith = 1 + 1, //~ ERROR arbitrary expressions aren't allowed in patterns + //~^ ERROR arbitrary expressions aren't allowed in patterns + //~^^ ERROR only char and numeric types are allowed in range patterns +}); + +fn main() {} + diff --git a/src/test/run-pass/macro-pat-neg-lit.rs b/src/test/run-pass/macro-pat-neg-lit.rs new file mode 100644 index 00000000000..43ac697edce --- /dev/null +++ b/src/test/run-pass/macro-pat-neg-lit.rs @@ -0,0 +1,35 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! enum_number { + ($name:ident { $($variant:ident = $value:expr, )* }) => { + enum $name { + $($variant = $value,)* + } + + fn foo(value: i32) -> Option<$name> { + match value { + $( $value => Some($name::$variant), )* + _ => None + } + } + } +} + +enum_number!(Change { + Down = -1, + None = 0, + Up = 1, +}); + +fn main() { + if let Some(Change::Down) = foo(-1) {} else { panic!() } +} + -- cgit 1.4.1-3-g733a5 From e03948ef3e19ff90066ca366bf76c390d7a42bc5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 25 Jun 2017 20:34:49 +0300 Subject: Make `$crate` a keyword --- src/librustc/hir/print.rs | 6 +- src/librustc_resolve/build_reduced_graph.rs | 5 +- src/librustc_resolve/lib.rs | 5 +- src/librustc_resolve/macros.rs | 2 +- src/libsyntax/ast.rs | 5 +- src/libsyntax/ext/tt/quoted.rs | 4 +- src/libsyntax/parse/token.rs | 3 +- src/libsyntax/print/pprust.rs | 4 +- src/libsyntax_pos/symbol.rs | 103 +++++++++++---------- src/test/compile-fail/dollar-crate-is-keyword-2.rs | 23 +++++ src/test/compile-fail/dollar-crate-is-keyword.rs | 24 +++++ src/test/compile-fail/use-self-type.rs | 21 +++++ 12 files changed, 139 insertions(+), 66 deletions(-) create mode 100644 src/test/compile-fail/dollar-crate-is-keyword-2.rs create mode 100644 src/test/compile-fail/dollar-crate-is-keyword.rs create mode 100644 src/test/compile-fail/use-self-type.rs (limited to 'src/libsyntax') diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index a78d5ce1c16..c6f4cd585d7 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1527,7 +1527,8 @@ impl<'a> State<'a> { if i > 0 { word(&mut self.s, "::")? } - if segment.name != keywords::CrateRoot.name() && segment.name != "$crate" { + if segment.name != keywords::CrateRoot.name() && + segment.name != keywords::DollarCrate.name() { self.print_name(segment.name)?; self.print_path_parameters(&segment.parameters, colons_before_params)?; } @@ -1554,7 +1555,8 @@ impl<'a> State<'a> { if i > 0 { word(&mut self.s, "::")? } - if segment.name != keywords::CrateRoot.name() && segment.name != "$crate" { + if segment.name != keywords::CrateRoot.name() && + segment.name != keywords::DollarCrate.name() { self.print_name(segment.name)?; self.print_path_parameters(&segment.parameters, colons_before_params)?; } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index b97c08b5bde..4b6b754dca6 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -149,14 +149,15 @@ impl<'a> Resolver<'a> { resolve_error(self, view_path.span, ResolutionError::SelfImportsOnlyAllowedWithin); - } else if source_name == "$crate" && full_path.segments.len() == 1 { + } else if source_name == keywords::DollarCrate.name() && + full_path.segments.len() == 1 { let crate_root = self.resolve_crate_root(source.ctxt); let crate_name = match crate_root.kind { ModuleKind::Def(_, name) => name, ModuleKind::Block(..) => unreachable!(), }; source.name = crate_name; - if binding.name == "$crate" { + if binding.name == keywords::DollarCrate.name() { binding.name = crate_name; } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8c11aa7def8..4bfe4d25ded 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2665,7 +2665,8 @@ impl<'a> Resolver<'a> { }; if path.len() > 1 && !global_by_default && result.base_def() != Def::Err && - path[0].name != keywords::CrateRoot.name() && path[0].name != "$crate" { + path[0].name != keywords::CrateRoot.name() && + path[0].name != keywords::DollarCrate.name() { let unqualified_result = { match self.resolve_path(&[*path.last().unwrap()], Some(ns), false, span) { PathResult::NonModule(path_res) => path_res.base_def(), @@ -2718,7 +2719,7 @@ impl<'a> Resolver<'a> { if i == 0 && ns == TypeNS && ident.name == keywords::CrateRoot.name() { module = Some(self.resolve_crate_root(ident.ctxt.modern())); continue - } else if i == 0 && ns == TypeNS && ident.name == "$crate" { + } else if i == 0 && ns == TypeNS && ident.name == keywords::DollarCrate.name() { module = Some(self.resolve_crate_root(ident.ctxt)); continue } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 60c07eda4d5..0fbc596f2e1 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -128,7 +128,7 @@ impl<'a> base::Resolver for Resolver<'a> { impl<'a, 'b> Folder for EliminateCrateVar<'a, 'b> { fn fold_path(&mut self, mut path: ast::Path) -> ast::Path { let ident = path.segments[0].identifier; - if ident.name == "$crate" { + if ident.name == keywords::DollarCrate.name() { path.segments[0].identifier.name = keywords::CrateRoot.name(); let module = self.0.resolve_crate_root(ident.ctxt); if !module.is_local() { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 8bd58ec7a52..ecab801d408 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -97,9 +97,8 @@ impl Path { } pub fn default_to_global(mut self) -> Path { - let name = self.segments[0].identifier.name; - if !self.is_global() && name != "$crate" && - name != keywords::SelfValue.name() && name != keywords::Super.name() { + if !self.is_global() && + !::parse::token::Ident(self.segments[0].identifier).is_path_segment_keyword() { self.segments.insert(0, PathSegment::crate_root()); } self diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index fa65e9501c2..c094a23cefc 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -12,7 +12,7 @@ use ast; use ext::tt::macro_parser; use parse::{ParseSess, token}; use print::pprust; -use symbol::{keywords, Symbol}; +use symbol::keywords; use syntax_pos::{DUMMY_SP, Span, BytePos}; use tokenstream; @@ -196,7 +196,7 @@ fn parse_tree(tree: tokenstream::TokenTree, Some(tokenstream::TokenTree::Token(ident_span, token::Ident(ident))) => { let span = Span { lo: span.lo, ..ident_span }; if ident.name == keywords::Crate.name() { - let ident = ast::Ident { name: Symbol::intern("$crate"), ..ident }; + let ident = ast::Ident { name: keywords::DollarCrate.name(), ..ident }; TokenTree::Token(span, token::Ident(ident)) } else { TokenTree::Token(span, token::SubstNt(ident)) diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 77db604c56e..d6a4dc2ee96 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -327,7 +327,8 @@ impl Token { match self.ident() { Some(id) => id.name == keywords::Super.name() || id.name == keywords::SelfValue.name() || - id.name == keywords::SelfType.name(), + id.name == keywords::SelfType.name() || + id.name == keywords::DollarCrate.name(), None => false, } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 34cda433d52..6c00e0b9efd 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -761,7 +761,7 @@ pub trait PrintState<'a> { word(self.writer(), "::")? } if segment.identifier.name != keywords::CrateRoot.name() && - segment.identifier.name != "$crate" { + segment.identifier.name != keywords::DollarCrate.name() { word(self.writer(), &segment.identifier.name.as_str())?; } } @@ -2375,7 +2375,7 @@ impl<'a> State<'a> { -> io::Result<()> { if segment.identifier.name != keywords::CrateRoot.name() && - segment.identifier.name != "$crate" { + segment.identifier.name != keywords::DollarCrate.name() { self.print_ident(segment.identifier)?; if let Some(ref parameters) = segment.parameters { self.print_path_parameters(parameters, colons_before_params)?; diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 6b5caff27e8..5e2e448f741 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -250,63 +250,64 @@ declare_keywords! { (4, Const, "const") (5, Continue, "continue") (6, Crate, "crate") - (7, Else, "else") - (8, Enum, "enum") - (9, Extern, "extern") - (10, False, "false") - (11, Fn, "fn") - (12, For, "for") - (13, If, "if") - (14, Impl, "impl") - (15, In, "in") - (16, Let, "let") - (17, Loop, "loop") - (18, Match, "match") - (19, Mod, "mod") - (20, Move, "move") - (21, Mut, "mut") - (22, Pub, "pub") - (23, Ref, "ref") - (24, Return, "return") - (25, SelfValue, "self") - (26, SelfType, "Self") - (27, Static, "static") - (28, Struct, "struct") - (29, Super, "super") - (30, Trait, "trait") - (31, True, "true") - (32, Type, "type") - (33, Unsafe, "unsafe") - (34, Use, "use") - (35, Where, "where") - (36, While, "while") + (7, DollarCrate, "$crate") + (8, Else, "else") + (9, Enum, "enum") + (10, Extern, "extern") + (11, False, "false") + (12, Fn, "fn") + (13, For, "for") + (14, If, "if") + (15, Impl, "impl") + (16, In, "in") + (17, Let, "let") + (18, Loop, "loop") + (19, Match, "match") + (20, Mod, "mod") + (21, Move, "move") + (22, Mut, "mut") + (23, Pub, "pub") + (24, Ref, "ref") + (25, Return, "return") + (26, SelfValue, "self") + (27, SelfType, "Self") + (28, Static, "static") + (29, Struct, "struct") + (30, Super, "super") + (31, Trait, "trait") + (32, True, "true") + (33, Type, "type") + (34, Unsafe, "unsafe") + (35, Use, "use") + (36, Where, "where") + (37, While, "while") // Keywords reserved for future use. - (37, Abstract, "abstract") - (38, Alignof, "alignof") - (39, Become, "become") - (40, Do, "do") - (41, Final, "final") - (42, Macro, "macro") - (43, Offsetof, "offsetof") - (44, Override, "override") - (45, Priv, "priv") - (46, Proc, "proc") - (47, Pure, "pure") - (48, Sizeof, "sizeof") - (49, Typeof, "typeof") - (50, Unsized, "unsized") - (51, Virtual, "virtual") - (52, Yield, "yield") + (38, Abstract, "abstract") + (39, Alignof, "alignof") + (40, Become, "become") + (41, Do, "do") + (42, Final, "final") + (43, Macro, "macro") + (44, Offsetof, "offsetof") + (45, Override, "override") + (46, Priv, "priv") + (47, Proc, "proc") + (48, Pure, "pure") + (49, Sizeof, "sizeof") + (50, Typeof, "typeof") + (51, Unsized, "unsized") + (52, Virtual, "virtual") + (53, Yield, "yield") // Weak keywords, have special meaning only in specific contexts. - (53, Default, "default") - (54, StaticLifetime, "'static") - (55, Union, "union") - (56, Catch, "catch") + (54, Default, "default") + (55, StaticLifetime, "'static") + (56, Union, "union") + (57, Catch, "catch") // A virtual keyword that resolves to the crate root when used in a lexical scope. - (57, CrateRoot, "{{root}}") + (58, CrateRoot, "{{root}}") } // If an interner exists in TLS, return it. Otherwise, prepare a fresh one. diff --git a/src/test/compile-fail/dollar-crate-is-keyword-2.rs b/src/test/compile-fail/dollar-crate-is-keyword-2.rs new file mode 100644 index 00000000000..e221fc6e9e0 --- /dev/null +++ b/src/test/compile-fail/dollar-crate-is-keyword-2.rs @@ -0,0 +1,23 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +mod a {} + +macro_rules! m { + () => { + use a::$crate; //~ ERROR unresolved import `a::$crate` + use a::$crate::b; //~ ERROR unresolved import `a::$crate::b` + type A = a::$crate; //~ ERROR cannot find type `$crate` in module `a` + } +} + +m!(); + +fn main() {} diff --git a/src/test/compile-fail/dollar-crate-is-keyword.rs b/src/test/compile-fail/dollar-crate-is-keyword.rs new file mode 100644 index 00000000000..0bd47a0e11a --- /dev/null +++ b/src/test/compile-fail/dollar-crate-is-keyword.rs @@ -0,0 +1,24 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +macro_rules! m { + () => { + struct $crate {} //~ ERROR expected identifier, found keyword `$crate` + + use $crate; // OK + //~^ WARN `$crate` may not be imported + use $crate as $crate; //~ ERROR expected identifier, found keyword `$crate` + //~^ WARN `$crate` may not be imported + } +} + +m!(); + +fn main() {} diff --git a/src/test/compile-fail/use-self-type.rs b/src/test/compile-fail/use-self-type.rs new file mode 100644 index 00000000000..6b5286bf0a7 --- /dev/null +++ b/src/test/compile-fail/use-self-type.rs @@ -0,0 +1,21 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S; + +impl S { + fn f() {} + fn g() { + use Self::f; //~ ERROR unresolved import + pub(in Self::f) struct Z; //~ ERROR Use of undeclared type or module `Self` + } +} + +fn main() {} -- cgit 1.4.1-3-g733a5 From b33fd6d75966411c3934cd6bde07bb1a653b2d83 Mon Sep 17 00:00:00 2001 From: petrochenkov Date: Thu, 29 Jun 2017 13:16:35 +0300 Subject: Change some terminology around keywords and reserved identifiers --- src/librustdoc/html/highlight.rs | 2 +- src/libsyntax/parse/lexer/mod.rs | 2 +- src/libsyntax/parse/parser.rs | 46 +++----- src/libsyntax/parse/token.rs | 27 +++-- src/libsyntax_pos/symbol.rs | 127 +++++++++++------------ src/test/compile-fail/dollar-crate-is-keyword.rs | 4 +- src/test/parse-fail/macro-keyword.rs | 2 +- 7 files changed, 100 insertions(+), 110 deletions(-) (limited to 'src/libsyntax') diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index a40d1e6bdc9..de8749c43d9 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -300,7 +300,7 @@ impl<'a> Classifier<'a> { "Some" | "None" | "Ok" | "Err" => Class::PreludeVal, "$crate" => Class::KeyWord, - _ if tas.tok.is_any_keyword() => Class::KeyWord, + _ if tas.tok.is_reserved_ident() => Class::KeyWord, _ => { if self.in_macro_nonterminal { diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index e2656bea483..a35b278a4b0 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1283,7 +1283,7 @@ impl<'a> StringReader<'a> { }); let keyword_checking_token = &token::Ident(keyword_checking_ident); let last_bpos = self.pos; - if keyword_checking_token.is_any_keyword() && + if keyword_checking_token.is_reserved_ident() && !keyword_checking_token.is_keyword(keywords::Static) { self.err_span_(start, last_bpos, "lifetimes cannot use keyword names"); } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5b0031b2f17..64506c4af46 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -511,14 +511,13 @@ impl<'a> Parser<'a> { } pub fn this_token_descr(&self) -> String { - let s = self.this_token_to_string(); - if self.token.is_strict_keyword() { - format!("keyword `{}`", s) - } else if self.token.is_reserved_keyword() { - format!("reserved keyword `{}`", s) - } else { - format!("`{}`", s) - } + let prefix = match &self.token { + t if t.is_special_ident() => "reserved identifier ", + t if t.is_used_keyword() => "keyword ", + t if t.is_unused_keyword() => "reserved keyword ", + _ => "", + }; + format!("{}`{}`", prefix, self.this_token_to_string()) } pub fn unexpected_last(&self, t: &token::Token) -> PResult<'a, T> { @@ -637,10 +636,12 @@ impl<'a> Parser<'a> { } pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> { - self.check_strict_keywords(); - self.check_reserved_keywords(); match self.token { token::Ident(i) => { + if self.token.is_reserved_ident() { + self.span_err(self.span, &format!("expected identifier, found {}", + self.this_token_descr())); + } self.bump(); Ok(i) } @@ -713,25 +714,6 @@ impl<'a> Parser<'a> { } } - /// Signal an error if the given string is a strict keyword - pub fn check_strict_keywords(&mut self) { - if self.token.is_strict_keyword() { - let token_str = self.this_token_to_string(); - let span = self.span; - self.span_err(span, - &format!("expected identifier, found keyword `{}`", - token_str)); - } - } - - /// Signal an error if the current token is a reserved keyword - pub fn check_reserved_keywords(&mut self) { - if self.token.is_reserved_keyword() { - let token_str = self.this_token_to_string(); - self.fatal(&format!("`{}` is a reserved keyword", token_str)).emit() - } - } - fn check_ident(&mut self) -> bool { if self.token.is_ident() { true @@ -2301,7 +2283,7 @@ impl<'a> Parser<'a> { ex = ExprKind::Break(lt, e); hi = self.prev_span; } else if self.token.is_keyword(keywords::Let) { - // Catch this syntax error here, instead of in `check_strict_keywords`, so + // Catch this syntax error here, instead of in `parse_ident`, so // that we can explicitly mention that let is not to be used as an expression let mut db = self.fatal("expected expression, found statement (`let`)"); db.note("variable declaration using `let` is a statement"); @@ -3540,7 +3522,7 @@ impl<'a> Parser<'a> { // Parse box pat let subpat = self.parse_pat()?; pat = PatKind::Box(subpat); - } else if self.token.is_ident() && !self.token.is_any_keyword() && + } else if self.token.is_ident() && !self.token.is_reserved_ident() && self.parse_as_ident() { // Parse ident @ pat // This can give false positives and parse nullary enums, @@ -3815,7 +3797,7 @@ impl<'a> Parser<'a> { fn is_union_item(&self) -> bool { self.token.is_keyword(keywords::Union) && - self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) + self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) } fn is_defaultness(&self) -> bool { diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index d6a4dc2ee96..75969cf2eb8 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -87,7 +87,7 @@ impl Lit { fn ident_can_begin_expr(ident: ast::Ident) -> bool { let ident_token: Token = Ident(ident); - !ident_token.is_any_keyword() || + !ident_token.is_reserved_ident() || ident_token.is_path_segment_keyword() || [ keywords::Do.name(), @@ -110,7 +110,7 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool { fn ident_can_begin_type(ident: ast::Ident) -> bool { let ident_token: Token = Ident(ident); - !ident_token.is_any_keyword() || + !ident_token.is_reserved_ident() || ident_token.is_path_segment_keyword() || [ keywords::For.name(), @@ -315,7 +315,7 @@ impl Token { pub fn is_path_start(&self) -> bool { self == &ModSep || self.is_qpath_start() || self.is_path() || - self.is_path_segment_keyword() || self.is_ident() && !self.is_any_keyword() + self.is_path_segment_keyword() || self.is_ident() && !self.is_reserved_ident() } /// Returns `true` if the token is a given keyword, `kw`. @@ -333,13 +333,17 @@ impl Token { } } - /// Returns `true` if the token is either a strict or reserved keyword. - pub fn is_any_keyword(&self) -> bool { - self.is_strict_keyword() || self.is_reserved_keyword() + // Returns true for reserved identifiers used internally for elided lifetimes, + // unnamed method parameters, crate root module, error recovery etc. + pub fn is_special_ident(&self) -> bool { + match self.ident() { + Some(id) => id.name <= keywords::DollarCrate.name(), + _ => false, + } } - /// Returns `true` if the token is a strict keyword. - pub fn is_strict_keyword(&self) -> bool { + /// Returns `true` if the token is a keyword used in the language. + pub fn is_used_keyword(&self) -> bool { match self.ident() { Some(id) => id.name >= keywords::As.name() && id.name <= keywords::While.name(), _ => false, @@ -347,12 +351,17 @@ impl Token { } /// Returns `true` if the token is a keyword reserved for possible future use. - pub fn is_reserved_keyword(&self) -> bool { + pub fn is_unused_keyword(&self) -> bool { match self.ident() { Some(id) => id.name >= keywords::Abstract.name() && id.name <= keywords::Yield.name(), _ => false, } } + + /// Returns `true` if the token is either a special identifier or a keyword. + pub fn is_reserved_ident(&self) -> bool { + self.is_special_ident() || self.is_used_keyword() || self.is_unused_keyword() + } } #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)] diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 5e2e448f741..debac70545a 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -237,77 +237,76 @@ macro_rules! declare_keywords {( // NB: leaving holes in the ident table is bad! a different ident will get // interned with the id from the hole, but it will be between the min and max // of the reserved words, and thus tagged as "reserved". -// After modifying this list adjust `is_strict_keyword`/`is_reserved_keyword`, +// After modifying this list adjust `is_special_ident`, `is_used_keyword`/`is_unused_keyword`, // this should be rarely necessary though if the keywords are kept in alphabetic order. declare_keywords! { - // Invalid identifier + // Special reserved identifiers used internally for elided lifetimes, + // unnamed method parameters, crate root module, error recovery etc. (0, Invalid, "") - - // Strict keywords used in the language. - (1, As, "as") - (2, Box, "box") - (3, Break, "break") - (4, Const, "const") - (5, Continue, "continue") - (6, Crate, "crate") - (7, DollarCrate, "$crate") - (8, Else, "else") - (9, Enum, "enum") - (10, Extern, "extern") - (11, False, "false") - (12, Fn, "fn") - (13, For, "for") - (14, If, "if") - (15, Impl, "impl") - (16, In, "in") - (17, Let, "let") - (18, Loop, "loop") - (19, Match, "match") - (20, Mod, "mod") - (21, Move, "move") - (22, Mut, "mut") - (23, Pub, "pub") - (24, Ref, "ref") - (25, Return, "return") - (26, SelfValue, "self") - (27, SelfType, "Self") - (28, Static, "static") - (29, Struct, "struct") - (30, Super, "super") - (31, Trait, "trait") - (32, True, "true") - (33, Type, "type") - (34, Unsafe, "unsafe") - (35, Use, "use") - (36, Where, "where") - (37, While, "while") + (1, CrateRoot, "{{root}}") + (2, DollarCrate, "$crate") + + // Keywords used in the language. + (3, As, "as") + (4, Box, "box") + (5, Break, "break") + (6, Const, "const") + (7, Continue, "continue") + (8, Crate, "crate") + (9, Else, "else") + (10, Enum, "enum") + (11, Extern, "extern") + (12, False, "false") + (13, Fn, "fn") + (14, For, "for") + (15, If, "if") + (16, Impl, "impl") + (17, In, "in") + (18, Let, "let") + (19, Loop, "loop") + (20, Match, "match") + (21, Mod, "mod") + (22, Move, "move") + (23, Mut, "mut") + (24, Pub, "pub") + (25, Ref, "ref") + (26, Return, "return") + (27, SelfValue, "self") + (28, SelfType, "Self") + (29, Static, "static") + (30, Struct, "struct") + (31, Super, "super") + (32, Trait, "trait") + (33, True, "true") + (34, Type, "type") + (35, Unsafe, "unsafe") + (36, Use, "use") + (37, Where, "where") + (38, While, "while") // Keywords reserved for future use. - (38, Abstract, "abstract") - (39, Alignof, "alignof") - (40, Become, "become") - (41, Do, "do") - (42, Final, "final") - (43, Macro, "macro") - (44, Offsetof, "offsetof") - (45, Override, "override") - (46, Priv, "priv") - (47, Proc, "proc") - (48, Pure, "pure") - (49, Sizeof, "sizeof") - (50, Typeof, "typeof") - (51, Unsized, "unsized") - (52, Virtual, "virtual") - (53, Yield, "yield") + (39, Abstract, "abstract") + (40, Alignof, "alignof") + (41, Become, "become") + (42, Do, "do") + (43, Final, "final") + (44, Macro, "macro") + (45, Offsetof, "offsetof") + (46, Override, "override") + (47, Priv, "priv") + (48, Proc, "proc") + (49, Pure, "pure") + (50, Sizeof, "sizeof") + (51, Typeof, "typeof") + (52, Unsized, "unsized") + (53, Virtual, "virtual") + (54, Yield, "yield") // Weak keywords, have special meaning only in specific contexts. - (54, Default, "default") - (55, StaticLifetime, "'static") - (56, Union, "union") - (57, Catch, "catch") - - // A virtual keyword that resolves to the crate root when used in a lexical scope. - (58, CrateRoot, "{{root}}") + (55, Default, "default") + (56, StaticLifetime, "'static") + (57, Union, "union") + (58, Catch, "catch") } // If an interner exists in TLS, return it. Otherwise, prepare a fresh one. diff --git a/src/test/compile-fail/dollar-crate-is-keyword.rs b/src/test/compile-fail/dollar-crate-is-keyword.rs index 0bd47a0e11a..70597a230a8 100644 --- a/src/test/compile-fail/dollar-crate-is-keyword.rs +++ b/src/test/compile-fail/dollar-crate-is-keyword.rs @@ -10,11 +10,11 @@ macro_rules! m { () => { - struct $crate {} //~ ERROR expected identifier, found keyword `$crate` + struct $crate {} //~ ERROR expected identifier, found reserved identifier `$crate` use $crate; // OK //~^ WARN `$crate` may not be imported - use $crate as $crate; //~ ERROR expected identifier, found keyword `$crate` + use $crate as $crate; //~ ERROR expected identifier, found reserved identifier `$crate` //~^ WARN `$crate` may not be imported } } diff --git a/src/test/parse-fail/macro-keyword.rs b/src/test/parse-fail/macro-keyword.rs index 6a7ccff1554..c7dcaf4137e 100644 --- a/src/test/parse-fail/macro-keyword.rs +++ b/src/test/parse-fail/macro-keyword.rs @@ -10,7 +10,7 @@ // compile-flags: -Z parse-only -fn macro() { //~ ERROR `macro` is a reserved keyword +fn macro() { //~ ERROR expected identifier, found reserved keyword `macro` } pub fn main() { -- cgit 1.4.1-3-g733a5 From 03660b647690c3dea12a20468f9f798bacd14d82 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Sat, 24 Jun 2017 16:20:27 +0900 Subject: Move unsized_tuple_coercion behind a feature gate. --- .../language-features/unsized-tuple-coercion.md | 27 ++++++++++++++++++++++ src/librustc_typeck/check/coercion.rs | 21 ++++++++++++++++- src/libsyntax/feature_gate.rs | 6 +++++ src/test/compile-fail/dst-bad-assign-3.rs | 2 ++ src/test/compile-fail/dst-bad-coerce1.rs | 2 ++ src/test/compile-fail/dst-bad-coerce3.rs | 2 ++ src/test/compile-fail/dst-bad-coerce4.rs | 2 ++ src/test/compile-fail/dst-bad-deep-2.rs | 2 ++ .../feature-gate-unsized_tuple_coercion.rs | 14 +++++++++++ src/test/run-pass-valgrind/dst-dtor-3.rs | 2 ++ src/test/run-pass-valgrind/dst-dtor-4.rs | 2 ++ src/test/run-pass/dst-irrefutable-bind.rs | 2 ++ src/test/run-pass/dst-raw.rs | 2 ++ src/test/run-pass/dst-trait-tuple.rs | 1 + src/test/run-pass/dst-tuple-sole.rs | 2 ++ src/test/run-pass/dst-tuple.rs | 1 + 16 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md create mode 100644 src/test/compile-fail/feature-gate-unsized_tuple_coercion.rs (limited to 'src/libsyntax') diff --git a/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md b/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md new file mode 100644 index 00000000000..c243737e1be --- /dev/null +++ b/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md @@ -0,0 +1,27 @@ +# `unsized_tuple_coercion` + +The tracking issue for this feature is: [#XXXXX] + +[#XXXXX]: https://github.com/rust-lang/rust/issues/XXXXX + +------------------------ + +This is a part of [RFC0401]. According to the RFC, there should be an implementation like this: + +```rust +impl<..., T, U: ?Sized> Unsized<(..., U)> for (..., T) where T: Unsized {} +``` + +This implementation is currently gated behind `#[feature(unsized_tuple_coercion)]` to avoid insta-stability. Therefore you can use it like this: + +```rust +#![feature(unsized_tuple_coercion)] + +fn main() { + let x : ([i32; 3], [i32; 3]) = ([1, 2, 3], [4, 5, 6]); + let y : &([i32; 3], [i32]) = &x; + assert_eq!(y.1[0], 4); +} +``` + +[RFC0401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 81aa59e956a..968e893b9a0 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -76,6 +76,7 @@ use rustc::ty::relate::RelateResult; use rustc::ty::subst::Subst; use errors::DiagnosticBuilder; use syntax::abi; +use syntax::feature_gate; use syntax::ptr::P; use syntax_pos; @@ -520,6 +521,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { coerce_source, &[coerce_target])); + let mut has_unsized_tuple_coercion = false; + // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where // inference might unify those two inner type variables later. @@ -527,7 +530,15 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { while let Some(obligation) = queue.pop_front() { debug!("coerce_unsized resolve step: {:?}", obligation); let trait_ref = match obligation.predicate { - ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(), + ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => { + if unsize_did == tr.def_id() { + if let ty::TyTuple(..) = tr.0.input_types().nth(1).unwrap().sty { + debug!("coerce_unsized: found unsized tuple coercion"); + has_unsized_tuple_coercion = true; + } + } + tr.clone() + } _ => { coercion.obligations.push(obligation); continue; @@ -557,6 +568,14 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { } } + if has_unsized_tuple_coercion && !self.tcx.sess.features.borrow().unsized_tuple_coercion { + feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, + "unsized_tuple_coercion", + self.cause.span, + feature_gate::GateIssue::Language, + feature_gate::EXPLAIN_UNSIZED_TUPLE_COERCION); + } + Ok(coercion) } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 74bf19b841e..5de9062de74 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -357,6 +357,9 @@ declare_features! ( // Allows a test to fail without failing the whole suite (active, allow_fail, "1.19.0", Some(42219)), + + // Allows unsized tuple coercion. + (active, unsized_tuple_coercion, "1.20.0", None), ); declare_features! ( @@ -1041,6 +1044,9 @@ pub const EXPLAIN_VIS_MATCHER: &'static str = pub const EXPLAIN_PLACEMENT_IN: &'static str = "placement-in expression syntax is experimental and subject to change."; +pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str = + "Unsized tuple coercion is not stable enough for use and is subject to change"; + struct PostExpansionVisitor<'a> { context: &'a Context<'a>, } diff --git a/src/test/compile-fail/dst-bad-assign-3.rs b/src/test/compile-fail/dst-bad-assign-3.rs index 3c089edf001..1c3bad5ba56 100644 --- a/src/test/compile-fail/dst-bad-assign-3.rs +++ b/src/test/compile-fail/dst-bad-assign-3.rs @@ -10,6 +10,8 @@ // Forbid assignment into a dynamically sized type. +#![feature(unsized_tuple_coercion)] + type Fat = (isize, &'static str, T); //~^ WARNING trait bounds are not (yet) enforced diff --git a/src/test/compile-fail/dst-bad-coerce1.rs b/src/test/compile-fail/dst-bad-coerce1.rs index 722ff8f25d6..b0de84a5300 100644 --- a/src/test/compile-fail/dst-bad-coerce1.rs +++ b/src/test/compile-fail/dst-bad-coerce1.rs @@ -10,6 +10,8 @@ // Attempt to change the type as well as unsizing. +#![feature(unsized_tuple_coercion)] + struct Fat { ptr: T } diff --git a/src/test/compile-fail/dst-bad-coerce3.rs b/src/test/compile-fail/dst-bad-coerce3.rs index 4dedae9331b..35a147c15bb 100644 --- a/src/test/compile-fail/dst-bad-coerce3.rs +++ b/src/test/compile-fail/dst-bad-coerce3.rs @@ -10,6 +10,8 @@ // Attempt to extend the lifetime as well as unsizing. +#![feature(unsized_tuple_coercion)] + struct Fat { ptr: T } diff --git a/src/test/compile-fail/dst-bad-coerce4.rs b/src/test/compile-fail/dst-bad-coerce4.rs index 2e78108a8de..874b7588ff9 100644 --- a/src/test/compile-fail/dst-bad-coerce4.rs +++ b/src/test/compile-fail/dst-bad-coerce4.rs @@ -10,6 +10,8 @@ // Attempt to coerce from unsized to sized. +#![feature(unsized_tuple_coercion)] + struct Fat { ptr: T } diff --git a/src/test/compile-fail/dst-bad-deep-2.rs b/src/test/compile-fail/dst-bad-deep-2.rs index 831afd27153..0c812b1d815 100644 --- a/src/test/compile-fail/dst-bad-deep-2.rs +++ b/src/test/compile-fail/dst-bad-deep-2.rs @@ -13,6 +13,8 @@ // because it would require stack allocation of an unsized temporary (*g in the // test). +#![feature(unsized_tuple_coercion)] + pub fn main() { let f: ([isize; 3],) = ([5, 6, 7],); let g: &([isize],) = &f; diff --git a/src/test/compile-fail/feature-gate-unsized_tuple_coercion.rs b/src/test/compile-fail/feature-gate-unsized_tuple_coercion.rs new file mode 100644 index 00000000000..4ddde011263 --- /dev/null +++ b/src/test/compile-fail/feature-gate-unsized_tuple_coercion.rs @@ -0,0 +1,14 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let _ : &(Send,) = &((),); + //~^ ERROR Unsized tuple coercion is not stable enough +} diff --git a/src/test/run-pass-valgrind/dst-dtor-3.rs b/src/test/run-pass-valgrind/dst-dtor-3.rs index b21f6434b54..1ae66a28a84 100644 --- a/src/test/run-pass-valgrind/dst-dtor-3.rs +++ b/src/test/run-pass-valgrind/dst-dtor-3.rs @@ -10,6 +10,8 @@ // no-prefer-dynamic +#![feature(unsized_tuple_coercion)] + static mut DROP_RAN: bool = false; struct Foo; diff --git a/src/test/run-pass-valgrind/dst-dtor-4.rs b/src/test/run-pass-valgrind/dst-dtor-4.rs index 810589de770..e416f25bc03 100644 --- a/src/test/run-pass-valgrind/dst-dtor-4.rs +++ b/src/test/run-pass-valgrind/dst-dtor-4.rs @@ -10,6 +10,8 @@ // no-prefer-dynamic +#![feature(unsized_tuple_coercion)] + static mut DROP_RAN: isize = 0; struct Foo; diff --git a/src/test/run-pass/dst-irrefutable-bind.rs b/src/test/run-pass/dst-irrefutable-bind.rs index bd6ad9207ad..b1d6c732e7f 100644 --- a/src/test/run-pass/dst-irrefutable-bind.rs +++ b/src/test/run-pass/dst-irrefutable-bind.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(unsized_tuple_coercion)] + struct Test(T); fn main() { diff --git a/src/test/run-pass/dst-raw.rs b/src/test/run-pass/dst-raw.rs index c82cbd75044..9ebfbee8a33 100644 --- a/src/test/run-pass/dst-raw.rs +++ b/src/test/run-pass/dst-raw.rs @@ -11,6 +11,8 @@ // Test DST raw pointers +#![feature(unsized_tuple_coercion)] + trait Trait { fn foo(&self) -> isize; } diff --git a/src/test/run-pass/dst-trait-tuple.rs b/src/test/run-pass/dst-trait-tuple.rs index ab60e95c74e..9803e26f5f8 100644 --- a/src/test/run-pass/dst-trait-tuple.rs +++ b/src/test/run-pass/dst-trait-tuple.rs @@ -11,6 +11,7 @@ #![allow(unused_features)] #![feature(box_syntax)] +#![feature(unsized_tuple_coercion)] type Fat = (isize, &'static str, T); diff --git a/src/test/run-pass/dst-tuple-sole.rs b/src/test/run-pass/dst-tuple-sole.rs index d3901a7555f..a788e25218e 100644 --- a/src/test/run-pass/dst-tuple-sole.rs +++ b/src/test/run-pass/dst-tuple-sole.rs @@ -11,6 +11,8 @@ // As dst-tuple.rs, but the unsized field is the only field in the tuple. +#![feature(unsized_tuple_coercion)] + type Fat = (T,); // x is a fat pointer diff --git a/src/test/run-pass/dst-tuple.rs b/src/test/run-pass/dst-tuple.rs index 130294feb6c..2f5b28495b8 100644 --- a/src/test/run-pass/dst-tuple.rs +++ b/src/test/run-pass/dst-tuple.rs @@ -11,6 +11,7 @@ #![allow(unknown_features)] #![feature(box_syntax)] +#![feature(unsized_tuple_coercion)] type Fat = (isize, &'static str, T); -- cgit 1.4.1-3-g733a5 From 141265dfe8eb345d3218c771db957a93d6c7f000 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Sun, 25 Jun 2017 07:32:00 +0900 Subject: Give a tracking-issue number for unsized tuple coercion. --- src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md | 4 ++-- src/libsyntax/feature_gate.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libsyntax') diff --git a/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md b/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md index c243737e1be..200a9c19462 100644 --- a/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md +++ b/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md @@ -1,8 +1,8 @@ # `unsized_tuple_coercion` -The tracking issue for this feature is: [#XXXXX] +The tracking issue for this feature is: [#42877] -[#XXXXX]: https://github.com/rust-lang/rust/issues/XXXXX +[#42877]: https://github.com/rust-lang/rust/issues/42877 ------------------------ diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 5de9062de74..df8ee189d21 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -359,7 +359,7 @@ declare_features! ( (active, allow_fail, "1.19.0", Some(42219)), // Allows unsized tuple coercion. - (active, unsized_tuple_coercion, "1.20.0", None), + (active, unsized_tuple_coercion, "1.20.0", Some(42877)), ); declare_features! ( -- cgit 1.4.1-3-g733a5 From da887074fc70a9f8d2afec8dbe6e2eeea6fc1406 Mon Sep 17 00:00:00 2001 From: est31 Date: Tue, 27 Jun 2017 04:26:52 +0200 Subject: Output line column info when panicking --- src/libcore/lib.rs | 11 ++++-- src/libcore/macros.rs | 10 +++-- src/libcore/panicking.rs | 30 +++++++++----- src/libcore/panicking_stage0.rs | 86 +++++++++++++++++++++++++++++++++++++++++ src/librustc_trans/mir/block.rs | 32 ++++++++------- src/libstd/macros.rs | 10 ++--- src/libstd/panicking.rs | 69 +++++++++++++++++++++++++++------ src/libstd/rt.rs | 2 +- src/libsyntax/ext/build.rs | 11 +++--- 9 files changed, 207 insertions(+), 54 deletions(-) create mode 100644 src/libcore/panicking_stage0.rs (limited to 'src/libsyntax') diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index b6ab1ecaf4e..5acc6c3848a 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -39,9 +39,9 @@ //! * `rust_begin_panic` - This function takes three arguments, a //! `fmt::Arguments`, a `&'static str`, and a `u32`. These three arguments //! dictate the panic message, the file at which panic was invoked, and the -//! line. It is up to consumers of this core library to define this panic -//! function; it is only required to never return. This requires a `lang` -//! attribute named `panic_fmt`. +//! line and column inside the file. It is up to consumers of this core +//! library to define this panic function; it is only required to never +//! return. This requires a `lang` attribute named `panic_fmt`. //! //! * `rust_eh_personality` - is used by the failure mechanisms of the //! compiler. This is often mapped to GCC's personality function, but crates @@ -160,6 +160,11 @@ pub mod array; pub mod sync; pub mod cell; pub mod char; +// FIXME: remove when SNAP +#[cfg(stage0)] +#[path = "panicking_stage0.rs"] +pub mod panicking; +#[cfg(not(stage0))] pub mod panicking; pub mod iter; pub mod option; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 5bb6a772aeb..c9761bbe611 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -17,16 +17,18 @@ macro_rules! panic { panic!("explicit panic") ); ($msg:expr) => ({ - static _MSG_FILE_LINE: (&'static str, &'static str, u32) = ($msg, file!(), line!()); - $crate::panicking::panic(&_MSG_FILE_LINE) + static _MSG_FILE_LINE_COL: (&'static str, &'static str, u32, u32) = + ($msg, file!(), line!(), column!()); + $crate::panicking::panic_new(&_MSG_FILE_LINE_COL) }); ($fmt:expr, $($arg:tt)*) => ({ // The leading _'s are to avoid dead code warnings if this is // used inside a dead function. Just `#[allow(dead_code)]` is // insufficient, since the user may have // `#[forbid(dead_code)]` and which cannot be overridden. - static _FILE_LINE: (&'static str, u32) = (file!(), line!()); - $crate::panicking::panic_fmt(format_args!($fmt, $($arg)*), &_FILE_LINE) + static _MSG_FILE_LINE_COL: (&'static str, u32, u32) = + (file!(), line!(), column!()); + $crate::panicking::panic_fmt_new(format_args!($fmt, $($arg)*), &_MSG_FILE_LINE_COL) }); } diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 60b7669f3b2..d4df0f69b90 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -17,7 +17,7 @@ //! //! ``` //! # use std::fmt; -//! fn panic_impl(fmt: fmt::Arguments, file_line: &(&'static str, u32)) -> ! +//! fn panic_impl(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! //! # { loop {} } //! ``` //! @@ -38,35 +38,45 @@ use fmt; +#[cold] #[inline(never)] +pub fn panic_new(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! { + panic(&expr_file_line_col) +} + #[cold] #[inline(never)] // this is the slow path, always #[lang = "panic"] -pub fn panic(expr_file_line: &(&'static str, &'static str, u32)) -> ! { +pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! { // Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially // reduce size overhead. The format_args! macro uses str's Display trait to // write expr, which calls Formatter::pad, which must accommodate string // truncation and padding (even though none is used here). Using // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the // output binary, saving up to a few kilobytes. - let (expr, file, line) = *expr_file_line; - panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), &(file, line)) + let (expr, file, line, col) = *expr_file_line_col; + panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), &(file, line, col)) } #[cold] #[inline(never)] #[lang = "panic_bounds_check"] -fn panic_bounds_check(file_line: &(&'static str, u32), +fn panic_bounds_check(file_line_col: &(&'static str, u32, u32), index: usize, len: usize) -> ! { panic_fmt(format_args!("index out of bounds: the len is {} but the index is {}", - len, index), file_line) + len, index), file_line_col) +} + +#[cold] #[inline(never)] +pub fn panic_fmt_new(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { + panic_fmt(fmt, &file_line_col) } #[cold] #[inline(never)] -pub fn panic_fmt(fmt: fmt::Arguments, file_line: &(&'static str, u32)) -> ! { +pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { #[allow(improper_ctypes)] extern { #[lang = "panic_fmt"] #[unwind] - fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32) -> !; + fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32, col :u32) -> !; } - let (file, line) = *file_line; - unsafe { panic_impl(fmt, file, line) } + let (file, line, col) = *file_line_col; + unsafe { panic_impl(fmt, file, line, col) } } diff --git a/src/libcore/panicking_stage0.rs b/src/libcore/panicking_stage0.rs new file mode 100644 index 00000000000..3506f6a93bc --- /dev/null +++ b/src/libcore/panicking_stage0.rs @@ -0,0 +1,86 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Panic support for libcore +//! +//! The core library cannot define panicking, but it does *declare* panicking. This +//! means that the functions inside of libcore are allowed to panic, but to be +//! useful an upstream crate must define panicking for libcore to use. The current +//! interface for panicking is: +//! +//! ``` +//! # use std::fmt; +//! fn panic_impl(fmt: fmt::Arguments, file_line: &(&'static str, u32)) -> ! +//! # { loop {} } +//! ``` +//! +//! This definition allows for panicking with any general message, but it does not +//! allow for failing with a `Box` value. The reason for this is that libcore +//! is not allowed to allocate. +//! +//! This module contains a few other panicking functions, but these are just the +//! necessary lang items for the compiler. All panics are funneled through this +//! one function. Currently, the actual symbol is declared in the standard +//! library, but the location of this may change over time. + +#![allow(dead_code, missing_docs)] +#![unstable(feature = "core_panic", + reason = "internal details of the implementation of the `panic!` \ + and related macros", + issue = "0")] + +use fmt; + +#[cold] #[inline(never)] +pub fn panic_new(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! { + let (expr, file, line, _) = *expr_file_line_col; + let expr_file_line = (expr, file, line); + panic(&expr_file_line) +} + +#[cold] #[inline(never)] // this is the slow path, always +#[lang = "panic"] +pub fn panic(expr_file_line: &(&'static str, &'static str, u32)) -> ! { + // Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially + // reduce size overhead. The format_args! macro uses str's Display trait to + // write expr, which calls Formatter::pad, which must accommodate string + // truncation and padding (even though none is used here). Using + // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the + // output binary, saving up to a few kilobytes. + let (expr, file, line) = *expr_file_line; + panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), &(file, line)) +} + +#[cold] #[inline(never)] +#[lang = "panic_bounds_check"] +fn panic_bounds_check(file_line: &(&'static str, u32), + index: usize, len: usize) -> ! { + panic_fmt(format_args!("index out of bounds: the len is {} but the index is {}", + len, index), file_line) +} + +#[cold] #[inline(never)] +pub fn panic_fmt_new(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { + let (file, line, _) = *file_line_col; + let file_line = (file, line); + panic_fmt(fmt, &file_line) +} + +#[cold] #[inline(never)] +pub fn panic_fmt(fmt: fmt::Arguments, file_line: &(&'static str, u32)) -> ! { + #[allow(improper_ctypes)] + extern { + #[lang = "panic_fmt"] + #[unwind] + fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32, col: u32) -> !; + } + let (file, line) = *file_line; + unsafe { panic_impl(fmt, file, line, 0) } +} diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 16972a1b1ae..48b166c61de 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -28,6 +28,7 @@ use type_of; use type_::Type; use syntax::symbol::Symbol; +use syntax_pos::Pos; use std::cmp; @@ -333,6 +334,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let filename = Symbol::intern(&loc.file.name).as_str(); let filename = C_str_slice(bcx.ccx, filename); let line = C_u32(bcx.ccx, loc.line as u32); + let col = C_u32(bcx.ccx, loc.col.to_usize() as u32 + 1); // Put together the arguments to the panic entry point. let (lang_item, args, const_err) = match *msg { @@ -347,29 +349,29 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { index: index as u64 })); - let file_line = C_struct(bcx.ccx, &[filename, line], false); - let align = llalign_of_min(bcx.ccx, common::val_ty(file_line)); - let file_line = consts::addr_of(bcx.ccx, - file_line, - align, - "panic_bounds_check_loc"); + let file_line_col = C_struct(bcx.ccx, &[filename, line, col], false); + let align = llalign_of_min(bcx.ccx, common::val_ty(file_line_col)); + let file_line_col = consts::addr_of(bcx.ccx, + file_line_col, + align, + "panic_bounds_check_loc"); (lang_items::PanicBoundsCheckFnLangItem, - vec![file_line, index, len], + vec![file_line_col, index, len], const_err) } mir::AssertMessage::Math(ref err) => { let msg_str = Symbol::intern(err.description()).as_str(); let msg_str = C_str_slice(bcx.ccx, msg_str); - let msg_file_line = C_struct(bcx.ccx, - &[msg_str, filename, line], + let msg_file_line_col = C_struct(bcx.ccx, + &[msg_str, filename, line, col], false); - let align = llalign_of_min(bcx.ccx, common::val_ty(msg_file_line)); - let msg_file_line = consts::addr_of(bcx.ccx, - msg_file_line, - align, - "panic_loc"); + let align = llalign_of_min(bcx.ccx, common::val_ty(msg_file_line_col)); + let msg_file_line_col = consts::addr_of(bcx.ccx, + msg_file_line_col, + align, + "panic_loc"); (lang_items::PanicFnLangItem, - vec![msg_file_line], + vec![msg_file_line_col], Some(ErrKind::Math(err.clone()))) } }; diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 9a4c5ec8f6b..6eb9faacf7f 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -41,10 +41,10 @@ macro_rules! panic { panic!("explicit panic") }); ($msg:expr) => ({ - $crate::rt::begin_panic($msg, { + $crate::rt::begin_panic_new($msg, { // static requires less code at runtime, more constant data - static _FILE_LINE: (&'static str, u32) = (file!(), line!()); - &_FILE_LINE + static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(), column!()); + &_FILE_LINE_COL }) }); ($fmt:expr, $($arg:tt)+) => ({ @@ -53,8 +53,8 @@ macro_rules! panic { // used inside a dead function. Just `#[allow(dead_code)]` is // insufficient, since the user may have // `#[forbid(dead_code)]` and which cannot be overridden. - static _FILE_LINE: (&'static str, u32) = (file!(), line!()); - &_FILE_LINE + static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(), column!()); + &_FILE_LINE_COL }) }); } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 6f46a73698f..1a8d3b09009 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -262,6 +262,7 @@ impl<'a> PanicInfo<'a> { pub struct Location<'a> { file: &'a str, line: u32, + col: u32, } impl<'a> Location<'a> { @@ -308,6 +309,28 @@ impl<'a> Location<'a> { pub fn line(&self) -> u32 { self.line } + + /// Returns the column from which the panic originated. + /// + /// # Examples + /// + /// ```should_panic + /// use std::panic; + /// + /// panic::set_hook(Box::new(|panic_info| { + /// if let Some(location) = panic_info.location() { + /// println!("panic occured at column {}", location.column()); + /// } else { + /// println!("panic occured but can't get location information..."); + /// } + /// })); + /// + /// panic!("Normal panic"); + /// ``` + #[unstable(feature = "panic_col", issue = "42939")] + pub fn column(&self) -> u32 { + self.col + } } fn default_hook(info: &PanicInfo) { @@ -329,6 +352,7 @@ fn default_hook(info: &PanicInfo) { let file = info.location.file; let line = info.location.line; + let col = info.location.col; let msg = match info.payload.downcast_ref::<&'static str>() { Some(s) => *s, @@ -342,8 +366,8 @@ fn default_hook(info: &PanicInfo) { let name = thread.as_ref().and_then(|t| t.name()).unwrap_or(""); let write = |err: &mut ::io::Write| { - let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}", - name, msg, file, line); + let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}:{}", + name, msg, file, line, col); #[cfg(feature = "backtrace")] { @@ -467,8 +491,9 @@ pub fn panicking() -> bool { #[unwind] pub extern fn rust_begin_panic(msg: fmt::Arguments, file: &'static str, - line: u32) -> ! { - begin_panic_fmt(&msg, &(file, line)) + line: u32, + col: u32) -> ! { + begin_panic_fmt(&msg, &(file, line, col)) } /// The entry point for panicking with a formatted message. @@ -482,7 +507,7 @@ pub extern fn rust_begin_panic(msg: fmt::Arguments, issue = "0")] #[inline(never)] #[cold] pub fn begin_panic_fmt(msg: &fmt::Arguments, - file_line: &(&'static str, u32)) -> ! { + file_line_col: &(&'static str, u32, u32)) -> ! { use fmt::Write; // We do two allocations here, unfortunately. But (a) they're @@ -492,7 +517,25 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, let mut s = String::new(); let _ = s.write_fmt(*msg); - begin_panic(s, file_line) + begin_panic_new(s, file_line_col) +} + +// FIXME: remove begin_panic and rename begin_panic_new to begin_panic when SNAP + +/// This is the entry point of panicking for panic!() and assert!(). +#[unstable(feature = "libstd_sys_internals", + reason = "used by the panic! macro", + issue = "0")] +#[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible +pub fn begin_panic_new(msg: M, file_line_col: &(&'static str, u32, u32)) -> ! { + // Note that this should be the only allocation performed in this code path. + // Currently this means that panic!() on OOM will invoke this code path, + // but then again we're not really ready for panic on OOM anyway. If + // we do start doing this, then we should propagate this allocation to + // be performed in the parent of this thread instead of the thread that's + // panicking. + + rust_panic_with_hook(Box::new(msg), file_line_col) } /// This is the entry point of panicking for panic!() and assert!(). @@ -508,7 +551,10 @@ pub fn begin_panic(msg: M, file_line: &(&'static str, u32)) -> ! // be performed in the parent of this thread instead of the thread that's // panicking. - rust_panic_with_hook(Box::new(msg), file_line) + let (file, line) = *file_line; + let file_line_col = (file, line, 0); + + rust_panic_with_hook(Box::new(msg), &file_line_col) } /// Executes the primary logic for a panic, including checking for recursive @@ -520,8 +566,8 @@ pub fn begin_panic(msg: M, file_line: &(&'static str, u32)) -> ! #[inline(never)] #[cold] fn rust_panic_with_hook(msg: Box, - file_line: &(&'static str, u32)) -> ! { - let (file, line) = *file_line; + file_line_col: &(&'static str, u32, u32)) -> ! { + let (file, line, col) = *file_line_col; let panics = update_panic_count(1); @@ -540,8 +586,9 @@ fn rust_panic_with_hook(msg: Box, let info = PanicInfo { payload: &*msg, location: Location { - file: file, - line: line, + file, + line, + col, }, }; HOOK_LOCK.read(); diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 06fd838ea06..2ee63527c14 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -25,7 +25,7 @@ // Reexport some of our utilities which are expected by other crates. -pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count}; +pub use panicking::{begin_panic_new, begin_panic, begin_panic_fmt, update_panic_count}; #[cfg(not(test))] #[lang = "start"] diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index a4580ea3939..412a3493208 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -11,7 +11,7 @@ use abi::Abi; use ast::{self, Ident, Generics, Expr, BlockCheckMode, UnOp, PatKind}; use attr; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::{Pos, Span, DUMMY_SP}; use codemap::{dummy_spanned, respan, Spanned}; use ext::base::ExtCtxt; use ptr::P; @@ -768,14 +768,15 @@ impl<'a> AstBuilder for ExtCtxt<'a> { let loc = self.codemap().lookup_char_pos(span.lo); let expr_file = self.expr_str(span, Symbol::intern(&loc.file.name)); let expr_line = self.expr_u32(span, loc.line as u32); - let expr_file_line_tuple = self.expr_tuple(span, vec![expr_file, expr_line]); - let expr_file_line_ptr = self.expr_addr_of(span, expr_file_line_tuple); + let expr_col = self.expr_u32(span, loc.col.to_usize() as u32 + 1); + let expr_loc_tuple = self.expr_tuple(span, vec![expr_file, expr_line, expr_col]); + let expr_loc_ptr = self.expr_addr_of(span, expr_loc_tuple); self.expr_call_global( span, - self.std_path(&["rt", "begin_panic"]), + self.std_path(&["rt", "begin_panic_new"]), vec![ self.expr_str(span, msg), - expr_file_line_ptr]) + expr_loc_ptr]) } fn expr_unreachable(&self, span: Span) -> P { -- cgit 1.4.1-3-g733a5