Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 6 pull requests #69851

Merged
merged 38 commits into from
Mar 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
f63b88c
Permit attributes on 'if' expressions
Aaron1011 Feb 16, 2020
e912d9d
Test #[allow(unused)] on `if` expression
Aaron1011 Feb 16, 2020
e9ec47b
Test that stmt_expr_attrs properly gates if-attrs
Aaron1011 Feb 19, 2020
9a299e4
Test trying to cfg-remove an `if` expression
Aaron1011 Feb 19, 2020
b00f674
Remove recovery test
Aaron1011 Feb 19, 2020
e11cdfd
Add run-pass test suggested by @joshtriplett
Aaron1011 Feb 19, 2020
7f19358
Move if-attr tests to their own directory
Aaron1011 Feb 19, 2020
1b681d6
Test that cfg-gated if-exprs are not type-checked
Aaron1011 Feb 19, 2020
37c2c38
Extent pretty-print test
Aaron1011 Feb 19, 2020
66b152c
Fix tabs
Aaron1011 Feb 19, 2020
e50fd5a
Update stderr
Aaron1011 Mar 4, 2020
0468929
move error allocation test to error.rs
RalfJung Mar 4, 2020
938f852
miri validation: debug-complain about unexpected errors
RalfJung Mar 4, 2020
4971d03
fix some cases of unexpected exceptions leaving validation
RalfJung Mar 5, 2020
85e1466
Fix typo
RalfJung Mar 6, 2020
ed3014a
use static strings instead of tcx
RalfJung Mar 6, 2020
af0c44c
Add test for issue-54239
JohnTitor Mar 9, 2020
fc8be08
Add test for issue-57200
JohnTitor Mar 9, 2020
437c07f
Add test for issue-57201
JohnTitor Mar 9, 2020
0005f29
Add test for issue-60473
JohnTitor Mar 9, 2020
95d4785
Add test for issue-64620
JohnTitor Mar 9, 2020
579ce86
Add test for issue-67166
JohnTitor Mar 9, 2020
58303b7
Use slices in preference to 0-terminated strings
tmiasko Mar 6, 2020
e54a829
Avoid unnecessary interning of enum variant part id
tmiasko Mar 6, 2020
676b9bc
unix: Don't override existing SIGSEGV/BUS handlers
cuviper Mar 3, 2020
ef98ec0
Add FIXMEs
JohnTitor Mar 9, 2020
925e9a2
rustc_parse: Use `Token::ident` where possible
petrochenkov Mar 4, 2020
f4a03c4
rustc_ast: Introduce `Token::uninterpolated_span`
petrochenkov Mar 4, 2020
43b27df
rustc_ast: Introduce `Token::uninterpolate`
petrochenkov Mar 7, 2020
5d7f67d
rustc_parse: Remove `Parser::normalized(_prev)_token`
petrochenkov Mar 7, 2020
9be233c
Use `Token::uninterpolate` in couple more places matching on `(Nt)Ident`
petrochenkov Mar 7, 2020
7a30bb1
Address review comments
petrochenkov Mar 9, 2020
4ec9975
Rollup merge of #69201 - Aaron1011:feature/permit-if-attr, r=Centril
Centril Mar 9, 2020
eaf6905
Rollup merge of #69685 - cuviper:soft-segv, r=sfackler
Centril Mar 9, 2020
c9bbfb9
Rollup merge of #69762 - RalfJung:validity-errors, r=oli-obk
Centril Mar 9, 2020
2409e70
Rollup merge of #69779 - tmiasko:di-cstr, r=nagisa
Centril Mar 9, 2020
2677d59
Rollup merge of #69801 - petrochenkov:nonorm, r=Centril
Centril Mar 9, 2020
7e903f8
Rollup merge of #69842 - JohnTitor:more-tests, r=Centril
Centril Mar 9, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions src/librustc/mir/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ fn print_backtrace(backtrace: &mut Backtrace) {
eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
}

impl From<ErrorHandled> for InterpErrorInfo<'tcx> {
impl From<ErrorHandled> for InterpErrorInfo<'_> {
fn from(err: ErrorHandled) -> Self {
match err {
ErrorHandled::Reported => err_inval!(ReferencedConstant),
Expand Down Expand Up @@ -291,7 +291,7 @@ pub enum InvalidProgramInfo<'tcx> {
Layout(layout::LayoutError<'tcx>),
}

impl fmt::Debug for InvalidProgramInfo<'tcx> {
impl fmt::Debug for InvalidProgramInfo<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use InvalidProgramInfo::*;
match self {
Expand Down Expand Up @@ -321,6 +321,8 @@ pub enum UndefinedBehaviorInfo {
RemainderByZero,
/// Overflowing inbounds pointer arithmetic.
PointerArithOverflow,
/// Invalid metadata in a wide pointer (using `str` to avoid allocations).
InvalidMeta(&'static str),
}

impl fmt::Debug for UndefinedBehaviorInfo {
Expand All @@ -338,6 +340,7 @@ impl fmt::Debug for UndefinedBehaviorInfo {
DivisionByZero => write!(f, "dividing by zero"),
RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"),
PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg),
}
}
}
Expand All @@ -354,8 +357,8 @@ pub enum UnsupportedOpInfo<'tcx> {
Unsupported(String),

/// When const-prop encounters a situation it does not support, it raises this error.
/// This must not allocate for performance reasons.
ConstPropUnsupported(&'tcx str),
/// This must not allocate for performance reasons (hence `str`, not `String`).
ConstPropUnsupported(&'static str),

// -- Everything below is not categorized yet --
FunctionAbiMismatch(Abi, Abi),
Expand Down Expand Up @@ -612,3 +615,19 @@ impl fmt::Debug for InterpError<'_> {
}
}
}

impl InterpError<'_> {
/// Some errors allocate to be created as they contain free-form strings.
/// And sometimes we want to be sure that did not happen as it is a
/// waste of resources.
pub fn allocates(&self) -> bool {
match self {
InterpError::MachineStop(_)
| InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
| InterpError::Unsupported(UnsupportedOpInfo::ValidationFailure(_))
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => true,
_ => false,
}
}
}
9 changes: 6 additions & 3 deletions src/librustc_ast/attr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,10 @@ impl MetaItem {
}

impl AttrItem {
pub fn span(&self) -> Span {
self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
}

pub fn meta(&self, span: Span) -> Option<MetaItem> {
Some(MetaItem {
path: self.path.clone(),
Expand Down Expand Up @@ -437,7 +441,7 @@ impl MetaItem {
I: Iterator<Item = TokenTree>,
{
// FIXME: Share code with `parse_path`.
let path = match tokens.next() {
let path = match tokens.next().map(TokenTree::uninterpolate) {
Some(TokenTree::Token(Token { kind: kind @ token::Ident(..), span }))
| Some(TokenTree::Token(Token { kind: kind @ token::ModSep, span })) => 'arm: {
let mut segments = if let token::Ident(name, _) = kind {
Expand All @@ -453,7 +457,7 @@ impl MetaItem {
};
loop {
if let Some(TokenTree::Token(Token { kind: token::Ident(name, _), span })) =
tokens.next()
tokens.next().map(TokenTree::uninterpolate)
{
segments.push(PathSegment::from_ident(Ident::new(name, span)));
} else {
Expand All @@ -470,7 +474,6 @@ impl MetaItem {
Path { span, segments }
}
Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt {
token::Nonterminal::NtIdent(ident, _) => Path::from_ident(ident),
token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span),
token::Nonterminal::NtPath(ref path) => path.clone(),
_ => return None,
Expand Down
93 changes: 69 additions & 24 deletions src/librustc_ast/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use rustc_macros::HashStable_Generic;
use rustc_span::symbol::kw;
use rustc_span::symbol::Symbol;
use rustc_span::{self, Span, DUMMY_SP};
use std::fmt;
use std::mem;
use std::borrow::Cow;
use std::{fmt, mem};

#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
#[derive(HashStable_Generic)]
Expand Down Expand Up @@ -225,8 +225,15 @@ pub enum TokenKind {
/* Literals */
Literal(Lit),

/* Name components */
/// Identifier token.
/// Do not forget about `NtIdent` when you want to match on identifiers.
/// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to
/// treat regular and interpolated identifiers in the same way.
Ident(ast::Name, /* is_raw */ bool),
/// Lifetime identifier token.
/// Do not forget about `NtLifetime` when you want to match on lifetime identifiers.
/// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to
/// treat regular and interpolated lifetime identifiers in the same way.
Lifetime(ast::Name),

Interpolated(Lrc<Nonterminal>),
Expand Down Expand Up @@ -328,6 +335,19 @@ impl Token {
mem::replace(self, Token::dummy())
}

/// For interpolated tokens, returns a span of the fragment to which the interpolated
/// token refers. For all other tokens this is just a regular span.
/// It is particularly important to use this for identifiers and lifetimes
/// for which spans affect name resolution and edition checks.
/// Note that keywords are also identifiers, so they should use this
/// if they keep spans or perform edition checks.
pub fn uninterpolated_span(&self) -> Span {
match &self.kind {
Interpolated(nt) => nt.span(),
_ => self.span,
}
}

pub fn is_op(&self) -> bool {
match self.kind {
OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
Expand All @@ -345,7 +365,7 @@ impl Token {

/// Returns `true` if the token can appear at the start of an expression.
pub fn can_begin_expr(&self) -> bool {
match self.kind {
match self.uninterpolate().kind {
Ident(name, is_raw) =>
ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
OpenDelim(..) | // tuple, array or block
Expand All @@ -363,12 +383,10 @@ impl Token {
Lifetime(..) | // labeled loop
Pound => true, // expression attributes
Interpolated(ref nt) => match **nt {
NtIdent(ident, is_raw) => ident_can_begin_expr(ident.name, ident.span, is_raw),
NtLiteral(..) |
NtExpr(..) |
NtBlock(..) |
NtPath(..) |
NtLifetime(..) => true,
NtPath(..) => true,
_ => false,
},
_ => false,
Expand All @@ -377,7 +395,7 @@ impl Token {

/// Returns `true` if the token can appear at the start of a type.
pub fn can_begin_type(&self) -> bool {
match self.kind {
match self.uninterpolate().kind {
Ident(name, is_raw) =>
ident_can_begin_type(name, self.span, is_raw), // type name or keyword
OpenDelim(Paren) | // tuple
Expand All @@ -391,8 +409,7 @@ impl Token {
Lt | BinOp(Shl) | // associated path
ModSep => true, // global path
Interpolated(ref nt) => match **nt {
NtIdent(ident, is_raw) => ident_can_begin_type(ident.name, ident.span, is_raw),
NtTy(..) | NtPath(..) | NtLifetime(..) => true,
NtTy(..) | NtPath(..) => true,
_ => false,
},
_ => false,
Expand Down Expand Up @@ -433,38 +450,48 @@ impl Token {
///
/// Keep this in sync with `Lit::from_token`.
pub fn can_begin_literal_or_bool(&self) -> bool {
match self.kind {
match self.uninterpolate().kind {
Literal(..) | BinOp(Minus) => true,
Ident(name, false) if name.is_bool_lit() => true,
Interpolated(ref nt) => match &**nt {
NtIdent(ident, false) if ident.name.is_bool_lit() => true,
NtExpr(e) | NtLiteral(e) => matches!(e.kind, ast::ExprKind::Lit(_)),
_ => false,
},
_ => false,
}
}

// A convenience function for matching on identifiers during parsing.
// Turns interpolated identifier (`$i: ident`) or lifetime (`$l: lifetime`) token
// into the regular identifier or lifetime token it refers to,
// otherwise returns the original token.
pub fn uninterpolate(&self) -> Cow<'_, Token> {
match &self.kind {
Interpolated(nt) => match **nt {
NtIdent(ident, is_raw) => {
Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span))
}
NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
_ => Cow::Borrowed(self),
},
_ => Cow::Borrowed(self),
}
}

/// Returns an identifier if this token is an identifier.
pub fn ident(&self) -> Option<(ast::Ident, /* is_raw */ bool)> {
match self.kind {
Ident(name, is_raw) => Some((ast::Ident::new(name, self.span), is_raw)),
Interpolated(ref nt) => match **nt {
NtIdent(ident, is_raw) => Some((ident, is_raw)),
_ => None,
},
let token = self.uninterpolate();
match token.kind {
Ident(name, is_raw) => Some((ast::Ident::new(name, token.span), is_raw)),
_ => None,
}
}

/// Returns a lifetime identifier if this token is a lifetime.
pub fn lifetime(&self) -> Option<ast::Ident> {
match self.kind {
Lifetime(name) => Some(ast::Ident::new(name, self.span)),
Interpolated(ref nt) => match **nt {
NtLifetime(ident) => Some(ident),
_ => None,
},
let token = self.uninterpolate();
match token.kind {
Lifetime(name) => Some(ast::Ident::new(name, token.span)),
_ => None,
}
}
Expand Down Expand Up @@ -714,6 +741,24 @@ pub enum Nonterminal {
#[cfg(target_arch = "x86_64")]
rustc_data_structures::static_assert_size!(Nonterminal, 40);

impl Nonterminal {
fn span(&self) -> Span {
match self {
NtItem(item) => item.span,
NtBlock(block) => block.span,
NtStmt(stmt) => stmt.span,
NtPat(pat) => pat.span,
NtExpr(expr) | NtLiteral(expr) => expr.span,
NtTy(ty) => ty.span,
NtIdent(ident, _) | NtLifetime(ident) => ident.span,
NtMeta(attr_item) => attr_item.span(),
NtPath(path) => path.span,
NtVis(vis) => vis.span,
NtTT(tt) => tt.span(),
}
}
}

impl PartialEq for Nonterminal {
fn eq(&self, rhs: &Self) -> bool {
match (self, rhs) {
Expand Down
7 changes: 7 additions & 0 deletions src/librustc_ast/tokenstream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,13 @@ impl TokenTree {
pub fn close_tt(span: DelimSpan, delim: DelimToken) -> TokenTree {
TokenTree::token(token::CloseDelim(delim), span.close)
}

pub fn uninterpolate(self) -> TokenTree {
match self {
TokenTree::Token(token) => TokenTree::Token(token.uninterpolate().into_owned()),
tt => tt,
}
}
}

impl<CTX> HashStable<CTX> for TokenStream
Expand Down
15 changes: 4 additions & 11 deletions src/librustc_ast/util/literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,23 +191,16 @@ impl Lit {
///
/// Keep this in sync with `Token::can_begin_literal_or_bool`.
pub fn from_token(token: &Token) -> Result<Lit, LitError> {
let lit = match token.kind {
let lit = match token.uninterpolate().kind {
token::Ident(name, false) if name.is_bool_lit() => {
token::Lit::new(token::Bool, name, None)
}
token::Literal(lit) => lit,
token::Interpolated(ref nt) => {
match &**nt {
token::NtIdent(ident, false) if ident.name.is_bool_lit() => {
let lit = token::Lit::new(token::Bool, ident.name, None);
return Lit::from_lit_token(lit, ident.span);
if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt {
if let ast::ExprKind::Lit(lit) = &expr.kind {
return Ok(lit.clone());
}
token::NtExpr(expr) | token::NtLiteral(expr) => {
if let ast::ExprKind::Lit(lit) = &expr.kind {
return Ok(lit.clone());
}
}
_ => {}
}
return Err(LitError::NotLiteral);
}
Expand Down
65 changes: 32 additions & 33 deletions src/librustc_builtin_macros/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,44 +156,43 @@ fn parse_args<'a>(
if p.token == token::Eof {
break;
} // accept trailing commas
if p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq) {
named = true;
let name = if let token::Ident(name, _) = p.normalized_token.kind {
match p.token.ident() {
Some((ident, _)) if p.look_ahead(1, |t| *t == token::Eq) => {
named = true;
p.bump();
name
} else {
unreachable!();
};
p.expect(&token::Eq)?;
let e = p.parse_expr()?;
if let Some(prev) = names.get(&ident.name) {
ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident))
.span_label(args[*prev].span, "previously here")
.span_label(e.span, "duplicate argument")
.emit();
continue;
}

p.expect(&token::Eq)?;
let e = p.parse_expr()?;
if let Some(prev) = names.get(&name) {
ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", name))
.span_label(args[*prev].span, "previously here")
.span_label(e.span, "duplicate argument")
.emit();
continue;
// Resolve names into slots early.
// Since all the positional args are already seen at this point
// if the input is valid, we can simply append to the positional
// args. And remember the names.
let slot = args.len();
names.insert(ident.name, slot);
args.push(e);
}

// Resolve names into slots early.
// Since all the positional args are already seen at this point
// if the input is valid, we can simply append to the positional
// args. And remember the names.
let slot = args.len();
names.insert(name, slot);
args.push(e);
} else {
let e = p.parse_expr()?;
if named {
let mut err = ecx
.struct_span_err(e.span, "positional arguments cannot follow named arguments");
err.span_label(e.span, "positional arguments must be before named arguments");
for pos in names.values() {
err.span_label(args[*pos].span, "named argument");
_ => {
let e = p.parse_expr()?;
if named {
let mut err = ecx.struct_span_err(
e.span,
"positional arguments cannot follow named arguments",
);
err.span_label(e.span, "positional arguments must be before named arguments");
for pos in names.values() {
err.span_label(args[*pos].span, "named argument");
}
err.emit();
}
err.emit();
args.push(e);
}
args.push(e);
}
}
Ok((fmtstr, args, names))
Expand Down
Loading