Rollup merge of #66271 - petrochenkov:abism, r=Centril

syntax: Keep string literals in ABIs and `asm!` more precisely

As a result we don't lose spans when `extern` functions or blocks are passed to proc macros, and also escape all string literals consistently.
Continuation of https://github.com/rust-lang/rust/pull/60679, which did a similar thing with all literals besides those in ABIs and `asm!`.

TODO: Add tests.

Fixes https://github.com/rust-lang/rust/issues/60493
Fixes https://github.com/rust-lang/rust/issues/64561
r? @Centril
This commit is contained in:
Yuki Okushi 2019-11-17 13:36:12 +09:00 committed by GitHub
commit b83d50d34f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 271 additions and 177 deletions

View File

@ -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),
}))

View File

@ -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,

View File

@ -778,13 +778,12 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
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<ast::StrLit, Option<Lit>> {
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<Lit> {
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

View File

@ -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<StrLit>,
visibility: Visibility,
mut attrs: Vec<Attribute>,
extern_sp: Span,
@ -1775,9 +1775,16 @@ fn parse_item_fn(
attrs: Vec<Attribute>,
header: FnHeader,
) -> PResult<'a, Option<P<Item>>> {
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.

View File

@ -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<StrLit> {
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<ast::Name>)> {
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(

View File

@ -287,7 +287,7 @@ fn parse_ty_bare_fn(&mut self, generic_params: Vec<GenericParam>) -> 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<GenericParam>) -> PResult<'a,
};
let decl = self.parse_fn_decl(cfg, false)?;
Ok(TyKind::BareFn(P(BareFnTy {
abi,
ext,
unsafety,
generic_params,
decl,

View File

@ -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<Signature> {
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<NodeId>, 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<NodeId>, 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)?;

View File

@ -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<Symbol>,
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<GenericParam>,
pub decl: P<FnDecl>,
}
@ -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<StrLit>,
pub items: Vec<ForeignItem>,
}
@ -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<StrLit>) -> Extern {
abi.map_or(Extern::Implicit, Extern::Explicit)
}
}
@ -2441,7 +2461,7 @@ pub struct FnHeader {
pub unsafety: Unsafety,
pub asyncness: Spanned<IsAsync>,
pub constness: Spanned<Constness>,
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,
}
}
}

View File

@ -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,

View File

@ -441,7 +441,7 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, 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<T: MutVisitor>(mut item: ImplItem, visitor: &mut
}
pub fn noop_visit_fn_header<T: MutVisitor>(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);
}

View File

@ -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<ast::Ident>,
@ -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 => {},

View File

@ -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<dyn base::MacResult + 'cx> {
-> Box<dyn MacResult + 'cx> {
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

View File

@ -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<ast::ExplicitSelf>,
arg_types: Vec<(Ident, P<ast::Ty>)>,
body: P<Expr>)
@ -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,

View File

@ -570,7 +570,6 @@
rust_2018_preview,
rust_begin_unwind,
rustc,
Rust,
RustcDecodable,
RustcEncodable,
rustc_allocator,

View File

@ -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");
}
}

View File

@ -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

View File

@ -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() {}

View File

@ -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<isize>) -> 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`.