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..f689e7f9622 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,18 +1283,26 @@ 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), } } - 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 }) } - fn error_on_invalid_abi(&self, 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: StrLit) { struct_span_err!( self.sess, abi.span, diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs index dadb91f8b3c..a56a7bf1802 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,39 @@ macro_rules! parse_lit { self.maybe_recover_from_bad_qpath(expr, true) } - /// Matches `lit = true | false | token_lit`. + /// 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 { + 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()); + 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 +1134,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 +1146,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 73099169879..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 @@ -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_unescaped == 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..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, Abi, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, 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; @@ -1212,40 +1212,34 @@ 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_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() { - let ast::Lit { span, kind, .. } = self.parse_lit()?; - match kind { - ast::LitKind::Str(symbol, _) => return Ok(Abi::new(symbol, span)), - 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 } } - span - } else { - self.prev_span - }; - Ok(Abi::new(sym::C, span)) + Err(None) => None, + } } /// We are parsing `async fn`. If we are on Rust 2015, emit an error. @@ -1337,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/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..bbf00825acb 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)] @@ -1745,7 +1772,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 +2155,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, } @@ -2411,24 +2438,17 @@ 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(StrLit), } -impl Abi { - pub fn new(symbol: Symbol, span: Span) -> Self { - Self { symbol, span } - } -} - -impl Default for Abi { - fn default() -> Self { - Self::new(sym::Rust, DUMMY_SP) +impl Extern { + pub fn from_abi(abi: Option) -> Extern { + abi.map_or(Extern::Implicit, Extern::Explicit) } } @@ -2441,7 +2461,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 +2470,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..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" | @@ -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..17a7cbddff9 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,10 @@ 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_literal(&abi.as_lit()); + self.nbsp(); + } self.bopen(); self.print_foreign_mod(nmod, &item.attrs); self.bclose(item.span); @@ -2805,7 +2808,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 +2828,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,18 +2869,21 @@ 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_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 => {}, diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 5fab101957a..bd345a9a7da 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,18 @@ 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 mut err = p.sess.span_diagnostic.struct_span_err(span, "expected string literal"); + err.span_label(span, "not a string literal"); + Err(err) + } + } +} + fn parse_inline_asm<'a>( cx: &mut ExtCtxt<'a>, sp: Span, @@ -144,7 +154,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 +199,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 +222,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 +235,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 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/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-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/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 diff --git a/src/test/ui/proc-macro/span-preservation.rs b/src/test/ui/proc-macro/span-preservation.rs index 55835cb88f4..b22e50c4c17 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] @@ -48,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 0290f4b2cc9..545c2fa5f40 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? @@ -46,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`.