From 266f5471272532989332117e8a2e0bacb5b94ccf Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 9 Nov 2019 22:05:20 +0300 Subject: [PATCH 1/6] ast: Keep `extern` qualifiers in functions more precisely --- src/librustc/hir/lowering.rs | 2 +- src/librustc/hir/lowering/item.rs | 12 +++++-- src/librustc_parse/parser/item.rs | 35 +++++++++++-------- src/librustc_parse/parser/mod.rs | 24 +++++-------- src/librustc_parse/parser/ty.rs | 4 +-- src/librustc_save_analysis/sig.rs | 17 ++++----- src/libsyntax/ast.rs | 27 ++++++++------ src/libsyntax/feature_gate/check.rs | 16 ++++++--- src/libsyntax/mut_visit.rs | 4 +-- src/libsyntax/print/pprust.rs | 22 ++++++++---- src/libsyntax_ext/deriving/generic/mod.rs | 7 ++-- src/test/ui/proc-macro/span-preservation.rs | 10 ++---- .../ui/proc-macro/span-preservation.stderr | 26 ++++++++------ 13 files changed, 118 insertions(+), 88 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index ef6a6ae23dc..12f6f66e96b 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1219,7 +1219,7 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_>) -> hir::T ImplTraitContext::disallowed(), ), unsafety: f.unsafety, - abi: this.lower_abi(f.abi), + abi: this.lower_extern(f.ext), decl: this.lower_fn_decl(&f.decl, None, false, None), param_names: this.lower_fn_params_to_names(&f.decl), })) diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs index 4cd42927868..2dc7e014445 100644 --- a/src/librustc/hir/lowering/item.rs +++ b/src/librustc/hir/lowering/item.rs @@ -735,7 +735,7 @@ fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem { fn lower_foreign_mod(&mut self, fm: &ForeignMod) -> hir::ForeignMod { hir::ForeignMod { - abi: self.lower_abi(fm.abi), + abi: fm.abi.map_or(abi::Abi::C, |abi| self.lower_abi(abi)), items: fm.items .iter() .map(|x| self.lower_foreign_item(x)) @@ -1283,7 +1283,7 @@ fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader { unsafety: h.unsafety, asyncness: self.lower_asyncness(h.asyncness.node), constness: h.constness.node, - abi: self.lower_abi(h.abi), + abi: self.lower_extern(h.ext), } } @@ -1294,6 +1294,14 @@ pub(super) fn lower_abi(&mut self, abi: Abi) -> abi::Abi { }) } + pub(super) fn lower_extern(&mut self, ext: Extern) -> abi::Abi { + match ext { + Extern::None => abi::Abi::Rust, + Extern::Implicit => abi::Abi::C, + Extern::Explicit(abi) => self.lower_abi(abi), + } + } + fn error_on_invalid_abi(&self, abi: Abi) { struct_span_err!( self.sess, diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 73099169879..fe86d03c6e7 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -114,7 +114,7 @@ fn parse_item_implementation( unsafety: Unsafety::Normal, asyncness: respan(fn_span, IsAsync::NotAsync), constness: respan(fn_span, Constness::NotConst), - abi, + ext: Extern::from_abi(abi), }; return self.parse_item_fn(lo, vis, attrs, header); } else if self.check(&token::OpenDelim(token::Brace)) { @@ -143,14 +143,14 @@ fn parse_item_implementation( if self.check_keyword(kw::Extern) { self.sess.gated_spans.gate(sym::const_extern_fn, lo.to(self.token.span)); } - let abi = self.parse_extern_abi()?; + let ext = self.parse_extern()?; self.bump(); // `fn` let header = FnHeader { unsafety, asyncness: respan(const_span, IsAsync::NotAsync), constness: respan(const_span, Constness::Const), - abi, + ext, }; return self.parse_item_fn(lo, vis, attrs, header); } @@ -193,7 +193,7 @@ fn parse_item_implementation( unsafety, asyncness, constness: respan(fn_span, Constness::NotConst), - abi: Abi::new(sym::Rust, fn_span), + ext: Extern::None, }; return self.parse_item_fn(lo, vis, attrs, header); } @@ -230,7 +230,7 @@ fn parse_item_implementation( unsafety: Unsafety::Normal, asyncness: respan(fn_span, IsAsync::NotAsync), constness: respan(fn_span, Constness::NotConst), - abi: Abi::new(sym::Rust, fn_span), + ext: Extern::None, }; return self.parse_item_fn(lo, vis, attrs, header); } @@ -242,14 +242,14 @@ fn parse_item_implementation( self.bump(); // `unsafe` // `{` is also expected after `unsafe`; in case of error, include it in the diagnostic. self.check(&token::OpenDelim(token::Brace)); - let abi = self.parse_extern_abi()?; + let ext = self.parse_extern()?; self.expect_keyword(kw::Fn)?; let fn_span = self.prev_span; let header = FnHeader { unsafety: Unsafety::Unsafe, asyncness: respan(fn_span, IsAsync::NotAsync), constness: respan(fn_span, Constness::NotConst), - abi, + ext, }; return self.parse_item_fn(lo, vis, attrs, header); } @@ -1100,7 +1100,7 @@ fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, ast::Ident> { fn parse_item_foreign_mod( &mut self, lo: Span, - abi: Abi, + abi: Option, visibility: Visibility, mut attrs: Vec, extern_sp: Span, @@ -1775,9 +1775,16 @@ fn parse_item_fn( attrs: Vec, header: FnHeader, ) -> PResult<'a, Option>> { + let is_c_abi = match header.ext { + ast::Extern::None => false, + ast::Extern::Implicit => true, + ast::Extern::Explicit(abi) => abi.symbol == sym::C, + }; let (ident, decl, generics) = self.parse_fn_sig(ParamCfg { is_self_allowed: false, - allow_c_variadic: header.abi.symbol == sym::C && header.unsafety == Unsafety::Unsafe, + // FIXME: Parsing should not depend on ABI or unsafety and + // the variadic parameter should always be parsed. + allow_c_variadic: is_c_abi && header.unsafety == Unsafety::Unsafe, is_name_required: |_| true, })?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; @@ -1905,11 +1912,11 @@ fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> { } let asyncness = respan(self.prev_span, asyncness); let unsafety = self.parse_unsafety(); - let (constness, unsafety, abi) = if is_const_fn { - (respan(const_span, Constness::Const), unsafety, Abi::default()) + let (constness, unsafety, ext) = if is_const_fn { + (respan(const_span, Constness::Const), unsafety, Extern::None) } else { - let abi = self.parse_extern_abi()?; - (respan(self.prev_span, Constness::NotConst), unsafety, abi) + let ext = self.parse_extern()?; + (respan(self.prev_span, Constness::NotConst), unsafety, ext) }; if !self.eat_keyword(kw::Fn) { // It is possible for `expect_one_of` to recover given the contents of @@ -1917,7 +1924,7 @@ fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> { // account for this. if !self.expect_one_of(&[], &[])? { unreachable!() } } - Ok(FnHeader { constness, unsafety, asyncness, abi }) + Ok(FnHeader { constness, unsafety, asyncness, ext }) } /// Parse the "signature", including the identifier, parameters, and generics of a function. diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index f62f0c9a268..2d05a696791 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -15,7 +15,7 @@ use crate::lexer::UnmatchedBrace; use syntax::ast::{ - self, Abi, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident, + self, Abi, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Extern, Ident, IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety, }; @@ -1212,23 +1212,20 @@ fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> { } /// Parses `extern string_literal?`. - /// If `extern` is not found, the Rust ABI is used. - /// If `extern` is found and a `string_literal` does not follow, the C ABI is used. - fn parse_extern_abi(&mut self) -> PResult<'a, Abi> { + fn parse_extern(&mut self) -> PResult<'a, Extern> { Ok(if self.eat_keyword(kw::Extern) { - self.parse_opt_abi()? + Extern::from_abi(self.parse_opt_abi()?) } else { - Abi::default() + Extern::None }) } /// Parses a string literal as an ABI spec. - /// If one is not found, the "C" ABI is used. - fn parse_opt_abi(&mut self) -> PResult<'a, Abi> { - let span = if self.token.can_begin_literal_or_bool() { + fn parse_opt_abi(&mut self) -> PResult<'a, Option> { + if self.token.can_begin_literal_or_bool() { let ast::Lit { span, kind, .. } = self.parse_lit()?; match kind { - ast::LitKind::Str(symbol, _) => return Ok(Abi::new(symbol, span)), + ast::LitKind::Str(symbol, _) => return Ok(Some(Abi { symbol, span })), ast::LitKind::Err(_) => {} _ => { self.struct_span_err(span, "non-string ABI literal") @@ -1241,11 +1238,8 @@ fn parse_opt_abi(&mut self) -> PResult<'a, Abi> { .emit(); } } - span - } else { - self.prev_span - }; - Ok(Abi::new(sym::C, span)) + } + Ok(None) } /// We are parsing `async fn`. If we are on Rust 2015, emit an error. diff --git a/src/librustc_parse/parser/ty.rs b/src/librustc_parse/parser/ty.rs index 4c7d1006183..8e6bc29be52 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/src/librustc_parse/parser/ty.rs @@ -287,7 +287,7 @@ fn parse_ty_bare_fn(&mut self, generic_params: Vec) -> PResult<'a, */ let unsafety = self.parse_unsafety(); - let abi = self.parse_extern_abi()?; + let ext = self.parse_extern()?; self.expect_keyword(kw::Fn)?; let cfg = ParamCfg { is_self_allowed: false, @@ -296,7 +296,7 @@ fn parse_ty_bare_fn(&mut self, generic_params: Vec) -> PResult<'a, }; let decl = self.parse_fn_decl(cfg, false)?; Ok(TyKind::BareFn(P(BareFnTy { - abi, + ext, unsafety, generic_params, decl, diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 50dfac62024..255938a193c 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -30,9 +30,8 @@ use rls_data::{SigElement, Signature}; use rustc::hir::def::{Res, DefKind}; -use syntax::ast::{self, NodeId}; +use syntax::ast::{self, Extern, NodeId}; use syntax::print::pprust; -use syntax_pos::sym; pub fn item_signature(item: &ast::Item, scx: &SaveContext<'_, '_>) -> Option { if !scx.config.signatures { @@ -157,9 +156,11 @@ fn text_sig(text: String) -> Signature { } } -fn push_abi(text: &mut String, abi: ast::Abi) { - if abi.symbol != sym::Rust { - text.push_str(&format!("extern \"{}\" ", abi.symbol)); +fn push_extern(text: &mut String, ext: Extern) { + match ext { + Extern::None => {} + Extern::Implicit => text.push_str("extern "), + Extern::Explicit(abi) => text.push_str(&format!("extern \"{}\" ", abi.symbol)), } } @@ -237,7 +238,7 @@ fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext<'_, if f.unsafety == ast::Unsafety::Unsafe { text.push_str("unsafe "); } - push_abi(&mut text, f.abi); + push_extern(&mut text, f.ext); text.push_str("fn("); let mut defs = vec![]; @@ -387,7 +388,7 @@ fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext<'_, if header.unsafety == ast::Unsafety::Unsafe { text.push_str("unsafe "); } - push_abi(&mut text, header.abi); + push_extern(&mut text, header.ext); text.push_str("fn "); let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?; @@ -936,7 +937,7 @@ fn make_method_signature( if m.header.unsafety == ast::Unsafety::Unsafe { text.push_str("unsafe "); } - push_abi(&mut text, m.header.abi); + push_extern(&mut text, m.header.ext); text.push_str("fn "); let mut sig = name_and_generics(text, 0, generics, id, ident, scx)?; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index d358efbe543..575795758ae 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1745,7 +1745,7 @@ pub struct Ty { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct BareFnTy { pub unsafety: Unsafety, - pub abi: Abi, + pub ext: Extern, pub generic_params: Vec, pub decl: P, } @@ -2128,7 +2128,7 @@ pub struct Mod { /// E.g., `extern { .. }` or `extern C { .. }`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct ForeignMod { - pub abi: Abi, + pub abi: Option, pub items: Vec, } @@ -2420,15 +2420,20 @@ pub struct Abi { pub span: Span, } -impl Abi { - pub fn new(symbol: Symbol, span: Span) -> Self { - Self { symbol, span } - } +/// `extern` qualifier on a function item or function type. +#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] +pub enum Extern { + None, + Implicit, + Explicit(Abi), } -impl Default for Abi { - fn default() -> Self { - Self::new(sym::Rust, DUMMY_SP) +impl Extern { + pub fn from_abi(abi: Option) -> Extern { + match abi { + Some(abi) => Extern::Explicit(abi), + None => Extern::Implicit, + } } } @@ -2441,7 +2446,7 @@ pub struct FnHeader { pub unsafety: Unsafety, pub asyncness: Spanned, pub constness: Spanned, - pub abi: Abi, + pub ext: Extern, } impl Default for FnHeader { @@ -2450,7 +2455,7 @@ fn default() -> FnHeader { unsafety: Unsafety::Normal, asyncness: dummy_spanned(IsAsync::NotAsync), constness: dummy_spanned(Constness::NotConst), - abi: Abi::default(), + ext: Extern::None, } } } diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index bd836eee42a..d90fa9addf7 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -258,6 +258,12 @@ fn check_abi(&self, abi: ast::Abi) { } } + fn check_extern(&self, ext: ast::Extern) { + if let ast::Extern::Explicit(abi) = ext { + self.check_abi(abi); + } + } + fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) { let has_fields = variants.iter().any(|variant| match variant.data { VariantData::Tuple(..) | VariantData::Struct(..) => true, @@ -388,7 +394,9 @@ fn visit_name(&mut self, sp: Span, name: ast::Name) { fn visit_item(&mut self, i: &'a ast::Item) { match i.kind { ast::ItemKind::ForeignMod(ref foreign_module) => { - self.check_abi(foreign_module.abi); + if let Some(abi) = foreign_module.abi { + self.check_abi(abi); + } } ast::ItemKind::Fn(..) => { @@ -511,7 +519,7 @@ fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) { fn visit_ty(&mut self, ty: &'a ast::Ty) { match ty.kind { ast::TyKind::BareFn(ref bare_fn_ty) => { - self.check_abi(bare_fn_ty.abi); + self.check_extern(bare_fn_ty.ext); } ast::TyKind::Never => { gate_feature_post!(&self, never_type, ty.span, @@ -605,7 +613,7 @@ fn visit_fn(&mut self, // Stability of const fn methods are covered in // `visit_trait_item` and `visit_impl_item` below; this is // because default methods don't pass through this point. - self.check_abi(header.abi); + self.check_extern(header.ext); } if fn_decl.c_variadic() { @@ -639,7 +647,7 @@ fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) { match ti.kind { ast::TraitItemKind::Method(ref sig, ref block) => { if block.is_none() { - self.check_abi(sig.header.abi); + self.check_extern(sig.header.ext); } if sig.decl.c_variadic() { gate_feature_post!(&self, c_variadic, ti.span, diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index f4ef993edb9..da3c885b860 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -441,7 +441,7 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { vis.visit_mt(mt); } TyKind::BareFn(bft) => { - let BareFnTy { unsafety: _, abi: _, generic_params, decl } = bft.deref_mut(); + let BareFnTy { unsafety: _, ext: _, generic_params, decl } = bft.deref_mut(); generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); vis.visit_fn_decl(decl); } @@ -974,7 +974,7 @@ pub fn noop_flat_map_impl_item(mut item: ImplItem, visitor: &mut } pub fn noop_visit_fn_header(header: &mut FnHeader, vis: &mut T) { - let FnHeader { unsafety: _, asyncness, constness: _, abi: _ } = header; + let FnHeader { unsafety: _, asyncness, constness: _, ext: _ } = header; vis.visit_asyncness(&mut asyncness.node); } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ef65a744e83..de28bd6cf83 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1013,7 +1013,7 @@ pub fn print_type(&mut self, ty: &ast::Ty) { self.pclose(); } ast::TyKind::BareFn(ref f) => { - self.print_ty_fn(f.abi, + self.print_ty_fn(f.ext, f.unsafety, &f.decl, None, @@ -1232,7 +1232,9 @@ fn print_associated_type(&mut self, } ast::ItemKind::ForeignMod(ref nmod) => { self.head("extern"); - self.print_abi(nmod.abi); + if let Some(abi) = nmod.abi { + self.print_abi(abi); + } self.bopen(); self.print_foreign_mod(nmod, &item.attrs); self.bclose(item.span); @@ -2805,7 +2807,7 @@ pub fn print_mutability(&mut self, mutbl: ast::Mutability) { } crate fn print_ty_fn(&mut self, - abi: ast::Abi, + ext: ast::Extern, unsafety: ast::Unsafety, decl: &ast::FnDecl, name: Option, @@ -2825,7 +2827,7 @@ pub fn print_mutability(&mut self, mutbl: ast::Mutability) { span: syntax_pos::DUMMY_SP, }; self.print_fn(decl, - ast::FnHeader { unsafety, abi, ..ast::FnHeader::default() }, + ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() }, name, &generics, &source_map::dummy_spanned(ast::VisibilityKind::Inherited)); @@ -2866,9 +2868,15 @@ pub fn print_mutability(&mut self, mutbl: ast::Mutability) { self.print_asyncness(header.asyncness.node); self.print_unsafety(header.unsafety); - if header.abi.symbol != sym::Rust { - self.word_nbsp("extern"); - self.print_abi(header.abi); + match header.ext { + ast::Extern::None => {} + ast::Extern::Implicit => { + self.word_nbsp("extern"); + } + ast::Extern::Explicit(abi) => { + self.word_nbsp("extern"); + self.print_abi(abi); + } } self.s.word("fn") diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index b24306def74..b6bf2f88161 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -182,7 +182,7 @@ use std::vec; use rustc_data_structures::thin_vec::ThinVec; -use syntax::ast::{self, Abi, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind}; +use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind}; use syntax::ast::{VariantData, GenericParamKind, GenericArg}; use syntax::attr; use syntax::source_map::respan; @@ -737,7 +737,6 @@ fn expand_struct_def(&self, self, type_ident, generics, - sym::Rust, explicit_self, tys, body) @@ -792,7 +791,6 @@ fn expand_enum_def(&self, self, type_ident, generics, - sym::Rust, explicit_self, tys, body) @@ -918,7 +916,6 @@ fn create_method(&self, trait_: &TraitDef<'_>, type_ident: Ident, generics: &Generics, - abi: Symbol, explicit_self: Option, arg_types: Vec<(Ident, P)>, body: P) @@ -953,7 +950,7 @@ fn create_method(&self, let sig = ast::FnSig { header: ast::FnHeader { unsafety, - abi: Abi::new(abi, trait_lo_sp), + ext: ast::Extern::None, ..ast::FnHeader::default() }, decl: fn_decl, diff --git a/src/test/ui/proc-macro/span-preservation.rs b/src/test/ui/proc-macro/span-preservation.rs index 55835cb88f4..8b8e12fcba6 100644 --- a/src/test/ui/proc-macro/span-preservation.rs +++ b/src/test/ui/proc-macro/span-preservation.rs @@ -1,9 +1,8 @@ -//~ ERROR mismatched types -// aux-build:test-macros.rs - // For each of these, we should get the appropriate type mismatch error message, // and the function should be echoed. +// aux-build:test-macros.rs + #[macro_use] extern crate test_macros; @@ -35,12 +34,9 @@ struct Bar { let y = Foo { a: 10, b: 10isize }; //~ ERROR has no field named `b` } -// FIXME: This doesn't work at the moment. See the one below. The pretty-printer -// injects a "C" between `extern` and `fn` which causes a "probably_eq" -// `TokenStream` mismatch. The lack of `"C"` should be preserved in the AST. #[recollect_attr] extern fn bar() { - 0 + 0 //~ ERROR mismatched types } #[recollect_attr] diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr index 0290f4b2cc9..9e9271f529c 100644 --- a/src/test/ui/proc-macro/span-preservation.stderr +++ b/src/test/ui/proc-macro/span-preservation.stderr @@ -1,10 +1,5 @@ error[E0308]: mismatched types - | - = note: expected type `()` - found type `{integer}` - -error[E0308]: mismatched types - --> $DIR/span-preservation.rs:12:20 + --> $DIR/span-preservation.rs:11:20 | LL | let x: usize = "hello"; | ^^^^^^^ expected usize, found reference @@ -13,7 +8,7 @@ LL | let x: usize = "hello"; found type `&'static str` error[E0308]: mismatched types - --> $DIR/span-preservation.rs:18:29 + --> $DIR/span-preservation.rs:17:29 | LL | fn b(x: Option) -> usize { | ----- expected `usize` because of return type @@ -22,13 +17,13 @@ LL | Some(x) => { return x }, | ^ expected usize, found isize error[E0308]: mismatched types - --> $DIR/span-preservation.rs:34:22 + --> $DIR/span-preservation.rs:33:22 | LL | let x = Foo { a: 10isize }; | ^^^^^^^ expected usize, found isize error[E0560]: struct `c::Foo` has no field named `b` - --> $DIR/span-preservation.rs:35:26 + --> $DIR/span-preservation.rs:34:26 | LL | let y = Foo { a: 10, b: 10isize }; | ^ `c::Foo` does not have this field @@ -36,7 +31,18 @@ LL | let y = Foo { a: 10, b: 10isize }; = note: available fields are: `a` error[E0308]: mismatched types - --> $DIR/span-preservation.rs:48:5 + --> $DIR/span-preservation.rs:39:5 + | +LL | extern fn bar() { + | - possibly return type missing here? +LL | 0 + | ^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/span-preservation.rs:44:5 | LL | extern "C" fn baz() { | - possibly return type missing here? From 00bc4496026a3168eed95e88c29f17dac2739d48 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 10 Nov 2019 00:44:59 +0300 Subject: [PATCH 2/6] ast: Keep string literals in ABIs precisely --- src/librustc/hir/lowering/item.rs | 6 ++--- src/librustc_parse/parser/item.rs | 4 +-- src/librustc_parse/parser/mod.rs | 11 +++++--- src/libsyntax/ast.rs | 42 ++++++++++++++++++++--------- src/libsyntax/feature_gate/check.rs | 6 ++--- src/libsyntax/print/pprust.rs | 10 +++---- 6 files changed, 49 insertions(+), 30 deletions(-) diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs index 2dc7e014445..f689e7f9622 100644 --- a/src/librustc/hir/lowering/item.rs +++ b/src/librustc/hir/lowering/item.rs @@ -1287,8 +1287,8 @@ fn lower_fn_header(&mut self, h: FnHeader) -> hir::FnHeader { } } - pub(super) fn lower_abi(&mut self, abi: Abi) -> abi::Abi { - abi::lookup(&abi.symbol.as_str()).unwrap_or_else(|| { + pub(super) fn lower_abi(&mut self, abi: StrLit) -> abi::Abi { + abi::lookup(&abi.symbol_unescaped.as_str()).unwrap_or_else(|| { self.error_on_invalid_abi(abi); abi::Abi::Rust }) @@ -1302,7 +1302,7 @@ pub(super) fn lower_extern(&mut self, ext: Extern) -> abi::Abi { } } - fn error_on_invalid_abi(&self, abi: Abi) { + fn error_on_invalid_abi(&self, abi: StrLit) { struct_span_err!( self.sess, abi.span, diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index fe86d03c6e7..3b824dc939f 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -1100,7 +1100,7 @@ fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, ast::Ident> { fn parse_item_foreign_mod( &mut self, lo: Span, - abi: Option, + abi: Option, visibility: Visibility, mut attrs: Vec, extern_sp: Span, @@ -1778,7 +1778,7 @@ fn parse_item_fn( let is_c_abi = match header.ext { ast::Extern::None => false, ast::Extern::Implicit => true, - ast::Extern::Explicit(abi) => abi.symbol == sym::C, + ast::Extern::Explicit(abi) => abi.symbol_unescaped == sym::C, }; let (ident, decl, generics) = self.parse_fn_sig(ParamCfg { is_self_allowed: false, diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 2d05a696791..2b49091192c 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -15,7 +15,7 @@ use crate::lexer::UnmatchedBrace; use syntax::ast::{ - self, Abi, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Extern, Ident, + self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Extern, Ident, IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety, }; @@ -1221,11 +1221,14 @@ fn parse_extern(&mut self) -> PResult<'a, Extern> { } /// Parses a string literal as an ABI spec. - fn parse_opt_abi(&mut self) -> PResult<'a, Option> { + fn parse_opt_abi(&mut self) -> PResult<'a, Option> { if self.token.can_begin_literal_or_bool() { - let ast::Lit { span, kind, .. } = self.parse_lit()?; + let ast::Lit { token: token::Lit { symbol, suffix, .. }, span, kind } + = self.parse_lit()?; match kind { - ast::LitKind::Str(symbol, _) => return Ok(Some(Abi { symbol, span })), + ast::LitKind::Str(symbol_unescaped, style) => return Ok(Some(StrLit { + style, symbol, suffix, span, symbol_unescaped, + })), ast::LitKind::Err(_) => {} _ => { self.struct_span_err(span, "non-string ABI literal") diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 575795758ae..dee493a708e 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1422,6 +1422,33 @@ pub struct Lit { pub span: Span, } +/// Same as `Lit`, but restricted to string literals. +#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] +pub struct StrLit { + /// The original literal token as written in source code. + pub style: StrStyle, + pub symbol: Symbol, + pub suffix: Option, + pub span: Span, + /// The unescaped "semantic" representation of the literal lowered from the original token. + /// FIXME: Remove this and only create the semantic representation during lowering to HIR. + pub symbol_unescaped: Symbol, +} + +impl StrLit { + crate fn as_lit(&self) -> Lit { + let token_kind = match self.style { + StrStyle::Cooked => token::Str, + StrStyle::Raw(n) => token::StrRaw(n), + }; + Lit { + token: token::Lit::new(token_kind, self.symbol, self.suffix), + span: self.span, + kind: LitKind::Str(self.symbol_unescaped, self.style), + } + } +} + // Clippy uses Hash and PartialEq /// Type of the integer literal based on provided suffix. #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, Hash, PartialEq)] @@ -2128,7 +2155,7 @@ pub struct Mod { /// E.g., `extern { .. }` or `extern C { .. }`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct ForeignMod { - pub abi: Option, + pub abi: Option, pub items: Vec, } @@ -2411,25 +2438,16 @@ pub fn span_with_attributes(&self) -> Span { } } -/// A reference to an ABI. -/// -/// In AST our notion of an ABI is still syntactic unlike in `rustc_target::spec::abi::Abi`. -#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, PartialEq)] -pub struct Abi { - pub symbol: Symbol, - pub span: Span, -} - /// `extern` qualifier on a function item or function type. #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] pub enum Extern { None, Implicit, - Explicit(Abi), + Explicit(StrLit), } impl Extern { - pub fn from_abi(abi: Option) -> Extern { + pub fn from_abi(abi: Option) -> Extern { match abi { Some(abi) => Extern::Explicit(abi), None => Extern::Implicit, diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index d90fa9addf7..abf9adefd3c 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -191,10 +191,10 @@ macro_rules! gate_feature_post { } impl<'a> PostExpansionVisitor<'a> { - fn check_abi(&self, abi: ast::Abi) { - let ast::Abi { symbol, span } = abi; + fn check_abi(&self, abi: ast::StrLit) { + let ast::StrLit { symbol_unescaped, span, .. } = abi; - match &*symbol.as_str() { + match &*symbol_unescaped.as_str() { // Stable "Rust" | "C" | diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index de28bd6cf83..17a7cbddff9 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1233,7 +1233,8 @@ fn print_associated_type(&mut self, ast::ItemKind::ForeignMod(ref nmod) => { self.head("extern"); if let Some(abi) = nmod.abi { - self.print_abi(abi); + self.print_literal(&abi.as_lit()); + self.nbsp(); } self.bopen(); self.print_foreign_mod(nmod, &item.attrs); @@ -2875,17 +2876,14 @@ pub fn print_mutability(&mut self, mutbl: ast::Mutability) { } ast::Extern::Explicit(abi) => { self.word_nbsp("extern"); - self.print_abi(abi); + self.print_literal(&abi.as_lit()); + self.nbsp(); } } self.s.word("fn") } - fn print_abi(&mut self, abi: ast::Abi) { - self.word_nbsp(format!("\"{}\"", abi.symbol)); - } - crate fn print_unsafety(&mut self, s: ast::Unsafety) { match s { ast::Unsafety::Normal => {}, From b85a3da421abad7d1936ec6e57e43c7b0ff10bd3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 10 Nov 2019 15:32:41 +0300 Subject: [PATCH 3/6] parse: Support parsing optional literals Revert weird renaming of the former `LitError::report` --- src/librustc_parse/parser/expr.rs | 31 +++++++++++++++++++------------ src/librustc_parse/parser/item.rs | 2 +- src/librustc_parse/parser/mod.rs | 15 +++++++-------- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index dadb91f8b3c..df2f6822465 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -778,13 +778,12 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P> { macro_rules! parse_lit { () => { - match self.parse_lit() { - Ok(literal) => { + match self.parse_opt_lit() { + Some(literal) => { hi = self.prev_span; ex = ExprKind::Lit(literal); } - Err(mut err) => { - err.cancel(); + None => { return Err(self.expected_expression_found()); } } @@ -1074,11 +1073,20 @@ macro_rules! parse_lit { self.maybe_recover_from_bad_qpath(expr, true) } - /// Matches `lit = true | false | token_lit`. pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> { + self.parse_opt_lit().ok_or_else(|| { + let msg = format!("unexpected token: {}", self.this_token_descr()); + self.span_fatal(self.token.span, &msg) + }) + } + + /// Matches `lit = true | false | token_lit`. + /// Returns `None` if the next token is not a literal. + pub(super) fn parse_opt_lit(&mut self) -> Option { let mut recovered = None; if self.token == token::Dot { - // Attempt to recover `.4` as `0.4`. + // Attempt to recover `.4` as `0.4`. We don't currently have any syntax where + // dot would follow an optional literal, so we do this unconditionally. recovered = self.look_ahead(1, |next_token| { if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = next_token.kind { @@ -1107,11 +1115,10 @@ pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> { match Lit::from_token(token) { Ok(lit) => { self.bump(); - Ok(lit) + Some(lit) } Err(LitError::NotLiteral) => { - let msg = format!("unexpected token: {}", self.this_token_descr()); - Err(self.span_fatal(token.span, &msg)) + None } Err(err) => { let span = token.span; @@ -1120,18 +1127,18 @@ pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> { _ => unreachable!(), }; self.bump(); - self.error_literal_from_token(err, lit, span); + self.report_lit_error(err, lit, span); // Pack possible quotes and prefixes from the original literal into // the error literal's symbol so they can be pretty-printed faithfully. let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None); let symbol = Symbol::intern(&suffixless_lit.to_string()); let lit = token::Lit::new(token::Err, symbol, lit.suffix); - Lit::from_lit_token(lit, span).map_err(|_| unreachable!()) + Some(Lit::from_lit_token(lit, span).unwrap_or_else(|_| unreachable!())) } } } - fn error_literal_from_token(&self, err: LitError, lit: token::Lit, span: Span) { + fn report_lit_error(&self, err: LitError, lit: token::Lit, span: Span) { // Checks if `s` looks like i32 or u1234 etc. fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { s.len() > 1 diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 3b824dc939f..8e6df0fa4f3 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -105,7 +105,7 @@ fn parse_item_implementation( return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?)); } - let abi = self.parse_opt_abi()?; + let abi = self.parse_opt_abi(); if self.eat_keyword(kw::Fn) { // EXTERN FUNCTION ITEM diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 2b49091192c..7757e00020a 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -1214,21 +1214,20 @@ fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> { /// Parses `extern string_literal?`. fn parse_extern(&mut self) -> PResult<'a, Extern> { Ok(if self.eat_keyword(kw::Extern) { - Extern::from_abi(self.parse_opt_abi()?) + Extern::from_abi(self.parse_opt_abi()) } else { Extern::None }) } /// Parses a string literal as an ABI spec. - fn parse_opt_abi(&mut self) -> PResult<'a, Option> { - if self.token.can_begin_literal_or_bool() { - let ast::Lit { token: token::Lit { symbol, suffix, .. }, span, kind } - = self.parse_lit()?; + fn parse_opt_abi(&mut self) -> Option { + if let Some(ast::Lit { token: token::Lit { symbol, suffix, .. }, span, kind }) + = self.parse_opt_lit() { match kind { - ast::LitKind::Str(symbol_unescaped, style) => return Ok(Some(StrLit { + ast::LitKind::Str(symbol_unescaped, style) => return Some(StrLit { style, symbol, suffix, span, symbol_unescaped, - })), + }), ast::LitKind::Err(_) => {} _ => { self.struct_span_err(span, "non-string ABI literal") @@ -1242,7 +1241,7 @@ fn parse_opt_abi(&mut self) -> PResult<'a, Option> { } } } - Ok(None) + None } /// We are parsing `async fn`. If we are on Rust 2015, emit an error. From a699f17483baeff87dc027331bce9a552a6b0624 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 10 Nov 2019 17:04:12 +0300 Subject: [PATCH 4/6] parse: Use string literal parsing in the `asm` macro --- src/librustc_parse/parser/expr.rs | 16 +++++++++ src/librustc_parse/parser/item.rs | 6 ++-- src/librustc_parse/parser/mod.rs | 54 +++++++------------------------ src/libsyntax_ext/asm.rs | 39 ++++++++++++++-------- 4 files changed, 56 insertions(+), 59 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index df2f6822465..be1dc4f19a7 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1073,6 +1073,22 @@ macro_rules! parse_lit { self.maybe_recover_from_bad_qpath(expr, true) } + pub fn parse_str_lit(&mut self) -> Result> { + match self.parse_opt_lit() { + Some(lit) => match lit.kind { + ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit { + style, + symbol: lit.token.symbol, + suffix: lit.token.suffix, + span: lit.span, + symbol_unescaped, + }), + _ => Err(Some(lit)), + } + None => Err(None), + } + } + pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> { self.parse_opt_lit().ok_or_else(|| { let msg = format!("unexpected token: {}", self.this_token_descr()); diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 8e6df0fa4f3..20b96d5cd62 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -3,9 +3,9 @@ use crate::maybe_whole; -use syntax::ast::{self, Abi, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, AnonConst, Item}; +use syntax::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, AnonConst, Item}; use syntax::ast::{ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind}; -use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness}; +use syntax::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness, Extern, StrLit}; use syntax::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind}; use syntax::ast::{Ty, TyKind, Generics, TraitRef, EnumDef, VariantData, StructField}; use syntax::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, FnSig, SelfKind, Param}; @@ -105,7 +105,7 @@ fn parse_item_implementation( return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?)); } - let abi = self.parse_opt_abi(); + let abi = self.parse_abi(); if self.eat_keyword(kw::Fn) { // EXTERN FUNCTION ITEM diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 7757e00020a..d5ec4611498 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -15,8 +15,8 @@ use crate::lexer::UnmatchedBrace; use syntax::ast::{ - self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Extern, Ident, - IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety, + self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Extern, Ident, StrLit, + IsAsync, MacDelimiter, Mutability, Visibility, VisibilityKind, Unsafety, }; use syntax::print::pprust; @@ -1214,34 +1214,32 @@ fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> { /// Parses `extern string_literal?`. fn parse_extern(&mut self) -> PResult<'a, Extern> { Ok(if self.eat_keyword(kw::Extern) { - Extern::from_abi(self.parse_opt_abi()) + Extern::from_abi(self.parse_abi()) } else { Extern::None }) } /// Parses a string literal as an ABI spec. - fn parse_opt_abi(&mut self) -> Option { - if let Some(ast::Lit { token: token::Lit { symbol, suffix, .. }, span, kind }) - = self.parse_opt_lit() { - match kind { - ast::LitKind::Str(symbol_unescaped, style) => return Some(StrLit { - style, symbol, suffix, span, symbol_unescaped, - }), - ast::LitKind::Err(_) => {} + fn parse_abi(&mut self) -> Option { + match self.parse_str_lit() { + Ok(str_lit) => Some(str_lit), + Err(Some(lit)) => match lit.kind { + ast::LitKind::Err(_) => None, _ => { - self.struct_span_err(span, "non-string ABI literal") + self.struct_span_err(lit.span, "non-string ABI literal") .span_suggestion( - span, + lit.span, "specify the ABI with a string literal", "\"C\"".to_string(), Applicability::MaybeIncorrect, ) .emit(); + None } } + Err(None) => None, } - None } /// We are parsing `async fn`. If we are on Rust 2015, emit an error. @@ -1333,34 +1331,6 @@ fn is_import_coupler(&mut self) -> bool { self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace) || *t == token::BinOp(token::Star)) } - - fn parse_optional_str(&mut self) -> Option<(Symbol, ast::StrStyle, Option)> { - let ret = match self.token.kind { - token::Literal(token::Lit { kind: token::Str, symbol, suffix }) => - (symbol, ast::StrStyle::Cooked, suffix), - token::Literal(token::Lit { kind: token::StrRaw(n), symbol, suffix }) => - (symbol, ast::StrStyle::Raw(n), suffix), - _ => return None - }; - self.bump(); - Some(ret) - } - - pub fn parse_str(&mut self) -> PResult<'a, (Symbol, StrStyle)> { - match self.parse_optional_str() { - Some((s, style, suf)) => { - let sp = self.prev_span; - self.expect_no_suffix(sp, "a string literal", suf); - Ok((s, style)) - } - _ => { - let msg = "expected string literal"; - let mut err = self.fatal(msg); - err.span_label(self.token.span, msg); - Err(err) - } - } - } } crate fn make_unclosed_delims_error( diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 5fab101957a..9b37143557e 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -2,19 +2,17 @@ // use State::*; +use errors::{DiagnosticBuilder, PResult}; use rustc_data_structures::thin_vec::ThinVec; - -use errors::DiagnosticBuilder; - -use syntax::ast; -use syntax_expand::base::{self, *}; -use syntax::token::{self, Token}; +use rustc_parse::parser::Parser; +use syntax_expand::base::*; +use syntax_pos::Span; +use syntax::{span_err, struct_span_err}; +use syntax::ast::{self, AsmDialect}; use syntax::ptr::P; use syntax::symbol::{kw, sym, Symbol}; -use syntax::ast::AsmDialect; -use syntax_pos::Span; +use syntax::token::{self, Token}; use syntax::tokenstream::{self, TokenStream}; -use syntax::{span_err, struct_span_err}; use rustc_error_codes::*; @@ -45,7 +43,7 @@ fn next(&self) -> State { pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream) - -> Box { + -> Box { let mut inline_asm = match parse_inline_asm(cx, sp, tts) { Ok(Some(inline_asm)) => inline_asm, Ok(None) => return DummyResult::any(sp), @@ -69,6 +67,19 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt<'_>, })) } +fn parse_asm_str<'a>(p: &mut Parser<'a>) -> PResult<'a, Symbol> { + match p.parse_str_lit() { + Ok(str_lit) => Ok(str_lit.symbol_unescaped), + Err(opt_lit) => { + let span = opt_lit.map_or(p.token.span, |lit| lit.span); + let msg = "expected string literal"; + let mut err = p.sess.span_diagnostic.struct_span_fatal(span, msg); + err.span_label(span, msg); + Err(err) + } + } +} + fn parse_inline_asm<'a>( cx: &mut ExtCtxt<'a>, sp: Span, @@ -144,7 +155,7 @@ fn parse_inline_asm<'a>( p.eat(&token::Comma); } - let (constraint, _) = p.parse_str()?; + let constraint = parse_asm_str(&mut p)?; let span = p.prev_span; @@ -189,7 +200,7 @@ fn parse_inline_asm<'a>( p.eat(&token::Comma); } - let (constraint, _) = p.parse_str()?; + let constraint = parse_asm_str(&mut p)?; if constraint.as_str().starts_with("=") { span_err!(cx, p.prev_span, E0662, @@ -212,7 +223,7 @@ fn parse_inline_asm<'a>( p.eat(&token::Comma); } - let (s, _) = p.parse_str()?; + let s = parse_asm_str(&mut p)?; if OPTIONS.iter().any(|&opt| s == opt) { cx.span_warn(p.prev_span, "expected a clobber, found an option"); @@ -225,7 +236,7 @@ fn parse_inline_asm<'a>( } } Options => { - let (option, _) = p.parse_str()?; + let option = parse_asm_str(&mut p)?; if option == sym::volatile { // Indicates that the inline assembly has side effects From 11580ced403211c8c422a952a2c5dabedf6812d6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 16 Nov 2019 20:11:05 +0300 Subject: [PATCH 5/6] Address review comments --- src/librustc_parse/parser/expr.rs | 3 +++ src/libsyntax/ast.rs | 5 +---- src/libsyntax_ext/asm.rs | 5 ++--- src/libsyntax_pos/symbol.rs | 1 - src/test/ui/asm/asm-parse-errors.stderr | 10 +++++----- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index be1dc4f19a7..a56a7bf1802 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/src/librustc_parse/parser/expr.rs @@ -1073,6 +1073,9 @@ macro_rules! parse_lit { self.maybe_recover_from_bad_qpath(expr, true) } + /// Returns a string literal if the next token is a string literal. + /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, + /// and returns `None` if the next token is not literal at all. pub fn parse_str_lit(&mut self) -> Result> { match self.parse_opt_lit() { Some(lit) => match lit.kind { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index dee493a708e..bbf00825acb 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2448,10 +2448,7 @@ pub enum Extern { impl Extern { pub fn from_abi(abi: Option) -> Extern { - match abi { - Some(abi) => Extern::Explicit(abi), - None => Extern::Implicit, - } + abi.map_or(Extern::Implicit, Extern::Explicit) } } diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 9b37143557e..bd345a9a7da 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -72,9 +72,8 @@ fn parse_asm_str<'a>(p: &mut Parser<'a>) -> PResult<'a, Symbol> { Ok(str_lit) => Ok(str_lit.symbol_unescaped), Err(opt_lit) => { let span = opt_lit.map_or(p.token.span, |lit| lit.span); - let msg = "expected string literal"; - let mut err = p.sess.span_diagnostic.struct_span_fatal(span, msg); - err.span_label(span, msg); + let mut err = p.sess.span_diagnostic.struct_span_err(span, "expected string literal"); + err.span_label(span, "not a string literal"); Err(err) } } diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index b3e9576f43f..86eaeeab5a4 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -570,7 +570,6 @@ rust_2018_preview, rust_begin_unwind, rustc, - Rust, RustcDecodable, RustcEncodable, rustc_allocator, diff --git a/src/test/ui/asm/asm-parse-errors.stderr b/src/test/ui/asm/asm-parse-errors.stderr index 9fe59d12e12..2b29332fef5 100644 --- a/src/test/ui/asm/asm-parse-errors.stderr +++ b/src/test/ui/asm/asm-parse-errors.stderr @@ -8,13 +8,13 @@ error: expected string literal --> $DIR/asm-parse-errors.rs:5:18 | LL | asm!("nop" : struct); - | ^^^^^^ expected string literal + | ^^^^^^ not a string literal error: expected string literal --> $DIR/asm-parse-errors.rs:6:30 | LL | asm!("mov %eax, $$0x2" : struct); - | ^^^^^^ expected string literal + | ^^^^^^ not a string literal error: expected `(`, found keyword `struct` --> $DIR/asm-parse-errors.rs:7:39 @@ -32,7 +32,7 @@ error: expected string literal --> $DIR/asm-parse-errors.rs:9:44 | LL | asm!("in %dx, %al" : "={al}"(result) : struct); - | ^^^^^^ expected string literal + | ^^^^^^ not a string literal error: expected `(`, found keyword `struct` --> $DIR/asm-parse-errors.rs:10:51 @@ -50,13 +50,13 @@ error: expected string literal --> $DIR/asm-parse-errors.rs:12:36 | LL | asm!("mov $$0x200, %eax" : : : struct); - | ^^^^^^ expected string literal + | ^^^^^^ not a string literal error: expected string literal --> $DIR/asm-parse-errors.rs:13:45 | LL | asm!("mov eax, 2" : "={eax}"(foo) : : : struct); - | ^^^^^^ expected string literal + | ^^^^^^ not a string literal error: inline assembly must be a string literal --> $DIR/asm-parse-errors.rs:14:10 From 28aec1beaa5e16b17143f993cab408debe1dcda5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 17 Nov 2019 01:11:35 +0300 Subject: [PATCH 6/6] Add some more tests --- src/test/ui/asm/asm-literal-escaping.rs | 12 ++++++++++ src/test/ui/proc-macro/span-preservation.rs | 10 ++++++++ .../ui/proc-macro/span-preservation.stderr | 24 ++++++++++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/asm/asm-literal-escaping.rs diff --git a/src/test/ui/asm/asm-literal-escaping.rs b/src/test/ui/asm/asm-literal-escaping.rs new file mode 100644 index 00000000000..8d464e752e6 --- /dev/null +++ b/src/test/ui/asm/asm-literal-escaping.rs @@ -0,0 +1,12 @@ +// build-pass +// only-x86_64 + +#![feature(asm)] + +fn main() { + unsafe { + // "nop" :: "r"(x) : "eax" : "volatile" + let x = 10; + asm!("\x6Eop" :: "\x72"(x) : "\x65ax" : "\x76olatile"); + } +} diff --git a/src/test/ui/proc-macro/span-preservation.rs b/src/test/ui/proc-macro/span-preservation.rs index 8b8e12fcba6..b22e50c4c17 100644 --- a/src/test/ui/proc-macro/span-preservation.rs +++ b/src/test/ui/proc-macro/span-preservation.rs @@ -44,4 +44,14 @@ extern "C" fn baz() { 0 //~ ERROR mismatched types } +#[recollect_attr] +extern "Rust" fn rust_abi() { + 0 //~ ERROR mismatched types +} + +#[recollect_attr] +extern "\x43" fn c_abi_escaped() { + 0 //~ ERROR mismatched types +} + fn main() {} diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr index 9e9271f529c..545c2fa5f40 100644 --- a/src/test/ui/proc-macro/span-preservation.stderr +++ b/src/test/ui/proc-macro/span-preservation.stderr @@ -52,7 +52,29 @@ LL | 0 = note: expected type `()` found type `{integer}` -error: aborting due to 6 previous errors +error[E0308]: mismatched types + --> $DIR/span-preservation.rs:49:5 + | +LL | extern "Rust" fn rust_abi() { + | - possibly return type missing here? +LL | 0 + | ^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/span-preservation.rs:54:5 + | +LL | extern "\x43" fn c_abi_escaped() { + | - possibly return type missing here? +LL | 0 + | ^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error: aborting due to 8 previous errors Some errors have detailed explanations: E0308, E0560. For more information about an error, try `rustc --explain E0308`.