Skip to content

Commit

Permalink
ast: Keep extern qualifiers in functions more precisely
Browse files Browse the repository at this point in the history
  • Loading branch information
petrochenkov committed Nov 16, 2019
1 parent 5f00849 commit 266f547
Show file tree
Hide file tree
Showing 13 changed files with 118 additions and 88 deletions.
2 changes: 1 addition & 1 deletion src/librustc/hir/lowering.rs
Expand Up @@ -1219,7 +1219,7 @@ impl<'a> LoweringContext<'a> {
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),
}))
Expand Down
12 changes: 10 additions & 2 deletions src/librustc/hir/lowering/item.rs
Expand Up @@ -735,7 +735,7 @@ impl LoweringContext<'_> {

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))
Expand Down Expand Up @@ -1283,7 +1283,7 @@ impl LoweringContext<'_> {
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),
}
}

Expand All @@ -1294,6 +1294,14 @@ impl LoweringContext<'_> {
})
}

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,
Expand Down
35 changes: 21 additions & 14 deletions src/librustc_parse/parser/item.rs
Expand Up @@ -114,7 +114,7 @@ impl<'a> Parser<'a> {
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)) {
Expand Down Expand Up @@ -143,14 +143,14 @@ impl<'a> Parser<'a> {
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);
}
Expand Down Expand Up @@ -193,7 +193,7 @@ impl<'a> Parser<'a> {
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);
}
Expand Down Expand Up @@ -230,7 +230,7 @@ impl<'a> Parser<'a> {
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);
}
Expand All @@ -242,14 +242,14 @@ impl<'a> Parser<'a> {
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);
}
Expand Down Expand Up @@ -1100,7 +1100,7 @@ impl<'a> Parser<'a> {
fn parse_item_foreign_mod(
&mut self,
lo: Span,
abi: Abi,
abi: Option<Abi>,
visibility: Visibility,
mut attrs: Vec<Attribute>,
extern_sp: Span,
Expand Down Expand Up @@ -1775,9 +1775,16 @@ impl<'a> Parser<'a> {
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 == 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()?;
Expand Down Expand Up @@ -1905,19 +1912,19 @@ impl<'a> Parser<'a> {
}
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
// `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
// 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.
Expand Down
24 changes: 9 additions & 15 deletions src/librustc_parse/parser/mod.rs
Expand Up @@ -15,7 +15,7 @@ use crate::{Directory, DirectoryOwnership};
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,
};

Expand Down Expand Up @@ -1212,23 +1212,20 @@ impl<'a> Parser<'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<Abi>> {
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")
Expand All @@ -1241,11 +1238,8 @@ impl<'a> Parser<'a> {
.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.
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_parse/parser/ty.rs
Expand Up @@ -287,7 +287,7 @@ impl<'a> Parser<'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,
Expand All @@ -296,7 +296,7 @@ impl<'a> Parser<'a> {
};
let decl = self.parse_fn_decl(cfg, false)?;
Ok(TyKind::BareFn(P(BareFnTy {
abi,
ext,
unsafety,
generic_params,
decl,
Expand Down
17 changes: 9 additions & 8 deletions src/librustc_save_analysis/sig.rs
Expand Up @@ -30,9 +30,8 @@ use crate::{id_from_def_id, id_from_node_id, SaveContext};
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 {
Expand Down Expand Up @@ -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)),
}
}

Expand Down Expand Up @@ -237,7 +238,7 @@ impl Sig for ast::Ty {
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![];
Expand Down Expand Up @@ -387,7 +388,7 @@ impl Sig for ast::Item {
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)?;
Expand Down Expand Up @@ -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)?;
Expand Down
27 changes: 16 additions & 11 deletions src/libsyntax/ast.rs
Expand Up @@ -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<GenericParam>,
pub decl: P<FnDecl>,
}
Expand Down Expand Up @@ -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<Abi>,
pub items: Vec<ForeignItem>,
}

Expand Down Expand Up @@ -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<Abi>) -> Extern {
match abi {
Some(abi) => Extern::Explicit(abi),
None => Extern::Implicit,
}
}
}

Expand All @@ -2441,7 +2446,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 {
Expand All @@ -2450,7 +2455,7 @@ impl Default for FnHeader {
unsafety: Unsafety::Normal,
asyncness: dummy_spanned(IsAsync::NotAsync),
constness: dummy_spanned(Constness::NotConst),
abi: Abi::default(),
ext: Extern::None,
}
}
}
Expand Down
16 changes: 12 additions & 4 deletions src/libsyntax/feature_gate/check.rs
Expand Up @@ -258,6 +258,12 @@ impl<'a> PostExpansionVisitor<'a> {
}
}

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,
Expand Down Expand Up @@ -388,7 +394,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
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(..) => {
Expand Down Expand Up @@ -511,7 +519,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
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,
Expand Down Expand Up @@ -605,7 +613,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
// 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() {
Expand Down Expand Up @@ -639,7 +647,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
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,
Expand Down

0 comments on commit 266f547

Please sign in to comment.