From 8300f51936149ec43eb063205e4d03c54a308f3c Mon Sep 17 00:00:00 2001 From: Nathan Corbyn Date: Sat, 23 Feb 2019 18:39:27 +0000 Subject: Deny `async fn` in 2015 edition Fix style issues and update diagnostic messages Update src/librustc_passes/diagnostics.rs Co-Authored-By: doctorn Deny nested `async fn` in Rust 2015 edition Deny nested `async fn` in Rust 2015 edition Deny nested `async fn` in Rust 2015 edition --- src/libsyntax/parse/parser.rs | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5a753e1f8c8..c257f05ae46 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5001,6 +5001,11 @@ impl<'a> Parser<'a> { ) } + fn is_async_fn(&mut self) -> bool { + self.token.is_keyword(keywords::Async) && + self.look_ahead(1, |t| t.is_keyword(keywords::Fn)) + } + fn is_do_catch_block(&mut self) -> bool { self.token.is_keyword(keywords::Do) && self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) && @@ -5133,7 +5138,8 @@ impl<'a> Parser<'a> { !self.is_union_item() && !self.is_crate_vis() && !self.is_existential_type_decl() && - !self.is_auto_trait_item() { + !self.is_auto_trait_item() && + !self.is_async_fn() { let pth = self.parse_path(PathStyle::Expr)?; if !self.eat(&token::Not) { @@ -6346,7 +6352,7 @@ impl<'a> Parser<'a> { /// Parses an item-position function declaration. fn parse_item_fn(&mut self, unsafety: Unsafety, - asyncness: IsAsync, + asyncness: Spanned, constness: Spanned, abi: Abi) -> PResult<'a, ItemInfo> { @@ -6378,7 +6384,7 @@ impl<'a> Parser<'a> { -> PResult<'a, ( Spanned, Unsafety, - IsAsync, + Spanned, Abi )> { @@ -6386,6 +6392,7 @@ impl<'a> Parser<'a> { let const_span = self.prev_span; let unsafety = self.parse_unsafety(); let asyncness = self.parse_asyncness(); + let asyncness = respan(self.prev_span, asyncness); let (constness, unsafety, abi) = if is_const_fn { (respan(const_span, Constness::Const), unsafety, Abi::Rust) } else { @@ -7796,7 +7803,7 @@ impl<'a> Parser<'a> { let abi = opt_abi.unwrap_or(Abi::C); let (ident, item_, extra_attrs) = self.parse_item_fn(Unsafety::Normal, - IsAsync::NotAsync, + respan(fn_span, IsAsync::NotAsync), respan(fn_span, Constness::NotConst), abi)?; let prev_span = self.prev_span; @@ -7840,7 +7847,7 @@ impl<'a> Parser<'a> { self.bump(); let (ident, item_, extra_attrs) = self.parse_item_fn(unsafety, - IsAsync::NotAsync, + respan(const_span, IsAsync::NotAsync), respan(const_span, Constness::Const), Abi::Rust)?; let prev_span = self.prev_span; @@ -7888,14 +7895,15 @@ impl<'a> Parser<'a> { // ASYNC FUNCTION ITEM let unsafety = self.parse_unsafety(); self.expect_keyword(keywords::Async)?; + let async_span = self.prev_span; self.expect_keyword(keywords::Fn)?; let fn_span = self.prev_span; let (ident, item_, extra_attrs) = self.parse_item_fn(unsafety, - IsAsync::Async { + respan(async_span, IsAsync::Async { closure_id: ast::DUMMY_NODE_ID, return_impl_trait_id: ast::DUMMY_NODE_ID, - }, + }), respan(fn_span, Constness::NotConst), Abi::Rust)?; let prev_span = self.prev_span; @@ -7904,6 +7912,13 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); + if self.span.rust_2015() { + self.diagnostic().struct_span_err_with_code( + async_span, + "`async fn` is not permitted in the 2015 edition", + DiagnosticId::Error("E0670".into()) + ).emit(); + } return Ok(Some(item)); } if self.check_keyword(keywords::Unsafe) && @@ -7951,7 +7966,7 @@ impl<'a> Parser<'a> { let fn_span = self.prev_span; let (ident, item_, extra_attrs) = self.parse_item_fn(Unsafety::Normal, - IsAsync::NotAsync, + respan(fn_span, IsAsync::NotAsync), respan(fn_span, Constness::NotConst), Abi::Rust)?; let prev_span = self.prev_span; @@ -7977,7 +7992,7 @@ impl<'a> Parser<'a> { let fn_span = self.prev_span; let (ident, item_, extra_attrs) = self.parse_item_fn(Unsafety::Unsafe, - IsAsync::NotAsync, + respan(fn_span, IsAsync::NotAsync), respan(fn_span, Constness::NotConst), abi)?; let prev_span = self.prev_span; @@ -8244,7 +8259,8 @@ impl<'a> Parser<'a> { lo: Span, visibility: Visibility ) -> PResult<'a, Option>> { - if macros_allowed && self.token.is_path_start() { + if macros_allowed && self.token.is_path_start() && + !(self.is_async_fn() && self.span.rust_2015()) { // MACRO INVOCATION ITEM let prev_span = self.prev_span; @@ -8299,7 +8315,8 @@ impl<'a> Parser<'a> { fn parse_assoc_macro_invoc(&mut self, item_kind: &str, vis: Option<&Visibility>, at_end: &mut bool) -> PResult<'a, Option> { - if self.token.is_path_start() { + if self.token.is_path_start() && + !(self.is_async_fn() && self.span.rust_2015()) { let prev_span = self.prev_span; let lo = self.span; let pth = self.parse_path(PathStyle::Mod)?; -- cgit 1.4.1-3-g733a5 From 58147d486bc26eb59d18d8e0d83aa6fe0b467fb9 Mon Sep 17 00:00:00 2001 From: Dan Robertson Date: Fri, 30 Nov 2018 15:53:44 +0000 Subject: Support defining C compatible variadic functions Add support for defining C compatible variadic functions in unsafe rust with extern "C". --- src/librustc/hir/intravisit.rs | 3 + src/librustc/hir/lowering.rs | 6 + src/librustc/hir/mod.rs | 3 + src/librustc/hir/print.rs | 3 + src/librustc/ich/impls_hir.rs | 3 +- src/librustc/middle/resolve_lifetime.rs | 31 ++-- src/librustc/ty/sty.rs | 6 +- src/librustc_codegen_llvm/abi.rs | 45 ++++- src/librustc_codegen_llvm/intrinsic.rs | 51 ++++-- src/librustc_codegen_llvm/mono_item.rs | 8 +- src/librustc_codegen_llvm/va_arg.rs | 4 +- src/librustc_codegen_ssa/mir/block.rs | 50 +++++- src/librustc_codegen_ssa/mir/mod.rs | 64 ++++++- src/librustc_codegen_ssa/traits/intrinsic.rs | 6 + src/librustc_lint/types.rs | 9 +- .../borrow_check/nll/type_check/mod.rs | 11 +- src/librustc_save_analysis/sig.rs | 1 + src/librustc_target/abi/call/mod.rs | 17 +- src/librustc_target/abi/call/x86.rs | 2 +- src/librustc_typeck/astconv.rs | 9 + src/librustc_typeck/check/callee.rs | 14 +- src/librustc_typeck/check/intrinsic.rs | 6 +- src/librustdoc/clean/mod.rs | 8 +- src/librustdoc/html/format.rs | 22 +-- src/libsyntax/ast.rs | 2 + src/libsyntax/mut_visit.rs | 3 +- src/libsyntax/parse/parser.rs | 106 ++++++----- src/libsyntax/print/pprust.rs | 3 + src/libsyntax/visit.rs | 2 +- src/test/codegen/c-variadic.rs | 69 +++++++ .../c-link-to-rust-va-list-fn/checkrust.rs | 27 ++- .../c-link-to-rust-va-list-fn/test.c | 10 ++ src/test/rustdoc/variadic.rs | 2 +- src/test/ui/c-variadic/variadic-ffi-1.rs | 31 ++++ src/test/ui/c-variadic/variadic-ffi-1.stderr | 9 + src/test/ui/c-variadic/variadic-ffi-2.rs | 8 + src/test/ui/c-variadic/variadic-ffi-2.stderr | 9 + src/test/ui/c-variadic/variadic-ffi-3.rs | 29 +++ src/test/ui/c-variadic/variadic-ffi-3.stderr | 76 ++++++++ src/test/ui/c-variadic/variadic-ffi-4.rs | 29 +++ src/test/ui/c-variadic/variadic-ffi-4.stderr | 198 +++++++++++++++++++++ src/test/ui/c-variadic/variadic-ffi-5.rs | 31 ++++ src/test/ui/c-variadic/variadic-ffi-5.stderr | 73 ++++++++ src/test/ui/c-variadic/variadic-ffi-6.rs | 12 ++ src/test/ui/c-variadic/variadic-ffi-6.stderr | 11 ++ src/test/ui/error-codes/E0617.rs | 4 +- src/test/ui/error-codes/E0617.stderr | 8 +- src/test/ui/parser/recover-enum2.stderr | 4 +- src/test/ui/variadic/variadic-ffi-2.rs | 8 - src/test/ui/variadic/variadic-ffi-2.stderr | 9 - src/test/ui/variadic/variadic-ffi-3.rs | 31 ---- src/test/ui/variadic/variadic-ffi-3.stderr | 76 -------- src/test/ui/variadic/variadic-ffi.rs | 31 ---- src/test/ui/variadic/variadic-ffi.stderr | 9 - 54 files changed, 999 insertions(+), 303 deletions(-) create mode 100644 src/test/codegen/c-variadic.rs create mode 100644 src/test/ui/c-variadic/variadic-ffi-1.rs create mode 100644 src/test/ui/c-variadic/variadic-ffi-1.stderr create mode 100644 src/test/ui/c-variadic/variadic-ffi-2.rs create mode 100644 src/test/ui/c-variadic/variadic-ffi-2.stderr create mode 100644 src/test/ui/c-variadic/variadic-ffi-3.rs create mode 100644 src/test/ui/c-variadic/variadic-ffi-3.stderr create mode 100644 src/test/ui/c-variadic/variadic-ffi-4.rs create mode 100644 src/test/ui/c-variadic/variadic-ffi-4.stderr create mode 100644 src/test/ui/c-variadic/variadic-ffi-5.rs create mode 100644 src/test/ui/c-variadic/variadic-ffi-5.stderr create mode 100644 src/test/ui/c-variadic/variadic-ffi-6.rs create mode 100644 src/test/ui/c-variadic/variadic-ffi-6.stderr delete mode 100644 src/test/ui/variadic/variadic-ffi-2.rs delete mode 100644 src/test/ui/variadic/variadic-ffi-2.stderr delete mode 100644 src/test/ui/variadic/variadic-ffi-3.rs delete mode 100644 src/test/ui/variadic/variadic-ffi-3.stderr delete mode 100644 src/test/ui/variadic/variadic-ffi.rs delete mode 100644 src/test/ui/variadic/variadic-ffi.stderr (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 0bc40da7e4f..8e4b9a5e8e6 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -617,6 +617,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { TyKind::Typeof(ref expression) => { visitor.visit_anon_const(expression) } + TyKind::CVarArgs(ref lt) => { + visitor.visit_lifetime(lt) + } TyKind::Infer | TyKind::Err => {} } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 0211dd72875..0e2b34d4fac 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1345,6 +1345,12 @@ impl<'a> LoweringContext<'a> { } } TyKind::Mac(_) => panic!("TyMac should have been expanded by now."), + TyKind::CVarArgs => { + // Create the implicit lifetime of the "spoofed" `VaList`. + let span = self.sess.source_map().next_point(t.span.shrink_to_lo()); + let lt = self.new_implicit_lifetime(span); + hir::TyKind::CVarArgs(lt) + }, }; let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(t.id); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 38e6e61592b..205109d18fe 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1829,6 +1829,9 @@ pub enum TyKind { Infer, /// Placeholder for a type that has failed to be defined. Err, + /// Placeholder for C-variadic arguments. We "spoof" the `VaList` created + /// from the variadic arguments. This type is only valid up to typeck. + CVarArgs(Lifetime), } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 17d37488413..8c252b0d027 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -434,6 +434,9 @@ impl<'a> State<'a> { self.s.word("/*ERROR*/")?; self.pclose()?; } + hir::TyKind::CVarArgs(_) => { + self.s.word("...")?; + } } self.end() } diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index d1161dda1e2..b7ec5889d6a 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -361,7 +361,8 @@ impl_stable_hash_for!(enum hir::TyKind { TraitObject(trait_refs, lifetime), Typeof(body_id), Err, - Infer + Infer, + CVarArgs(lt), }); impl_stable_hash_for!(struct hir::FnDecl { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 31e9eb9b746..832391d4416 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -764,6 +764,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }); } } + hir::TyKind::CVarArgs(ref lt) => { + // Resolve the generated lifetime for the C-variadic arguments. + // The lifetime is generated in AST -> HIR lowering. + if lt.name.is_elided() { + self.resolve_elided_lifetimes(vec![lt]) + } + } _ => intravisit::walk_ty(self, ty), } } @@ -2225,18 +2232,22 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { if let hir::TyKind::BareFn(_) = ty.node { self.outer_index.shift_in(1); } - if let hir::TyKind::TraitObject(ref bounds, ref lifetime) = ty.node { - for bound in bounds { - self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); - } + match ty.node { + hir::TyKind::TraitObject(ref bounds, ref lifetime) => { + for bound in bounds { + self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); + } - // Stay on the safe side and don't include the object - // lifetime default (which may not end up being used). - if !lifetime.is_elided() { - self.visit_lifetime(lifetime); + // Stay on the safe side and don't include the object + // lifetime default (which may not end up being used). + if !lifetime.is_elided() { + self.visit_lifetime(lifetime); + } + } + hir::TyKind::CVarArgs(_) => {} + _ => { + intravisit::walk_ty(self, ty); } - } else { - intravisit::walk_ty(self, ty); } if let hir::TyKind::BareFn(_) = ty.node { self.outer_index.shift_out(1); diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index df8b14b1f10..7ade035ce89 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -977,9 +977,9 @@ impl<'tcx> PolyGenSig<'tcx> { /// Signature of a function type, which I have arbitrarily /// decided to use to refer to the input/output types. /// -/// - `inputs` is the list of arguments and their modes. -/// - `output` is the return type. -/// - `variadic` indicates whether this is a variadic function. (only true for foreign fns) +/// - `inputs`: is the list of arguments and their modes. +/// - `output`: is the return type. +/// - `variadic`: indicates whether this is a C-variadic function. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct FnSig<'tcx> { pub inputs_and_output: &'tcx List>, diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 992149f7a47..aea62360651 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -258,7 +258,7 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> { val }; match self.mode { - PassMode::Ignore => {}, + PassMode::Ignore(_) => {} PassMode::Pair(..) => { OperandValue::Pair(next(), next()).store(bx, dst); } @@ -507,6 +507,14 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { } }; + // Store the index of the last argument. This is useful for working with + // C-compatible variadic arguments. + let last_arg_idx = if sig.inputs().is_empty() { + None + } else { + Some(sig.inputs().len() - 1) + }; + let arg_of = |ty: Ty<'tcx>, arg_idx: Option| { let is_return = arg_idx.is_none(); let mut arg = mk_arg_type(ty, arg_idx); @@ -516,7 +524,30 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { // The same is true for s390x-unknown-linux-gnu // and sparc64-unknown-linux-gnu. if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) { - arg.mode = PassMode::Ignore; + arg.mode = PassMode::Ignore(IgnoreMode::Zst); + } + } + + // If this is a C-variadic function, this is not the return value, + // and there is one or more fixed arguments; ensure that the `VaList` + // is ignored as an argument. + if sig.variadic { + match (last_arg_idx, arg_idx) { + (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => { + let va_list_did = match cx.tcx.lang_items().va_list() { + Some(did) => did, + None => bug!("`va_list` lang item required for C-variadic functions"), + }; + match ty.sty { + ty::Adt(def, _) if def.did == va_list_did => { + // This is the "spoofed" `VaList`. Set the arguments mode + // so that it will be ignored. + arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs); + }, + _ => (), + } + } + _ => {} } } @@ -646,7 +677,9 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { ); let llreturn_ty = match self.ret.mode { - PassMode::Ignore => cx.type_void(), + PassMode::Ignore(IgnoreMode::Zst) => cx.type_void(), + PassMode::Ignore(IgnoreMode::CVarArgs) => + bug!("`va_list` should never be a return type"), PassMode::Direct(_) | PassMode::Pair(..) => { self.ret.layout.immediate_llvm_type(cx) } @@ -664,7 +697,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { } let llarg_ty = match arg.mode { - PassMode::Ignore => continue, + PassMode::Ignore(_) => continue, PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx), PassMode::Pair(..) => { llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true)); @@ -733,7 +766,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { apply(&ArgAttributes::new()); } match arg.mode { - PassMode::Ignore => {} + PassMode::Ignore(_) => {} PassMode::Direct(ref attrs) | PassMode::Indirect(ref attrs, None) => apply(attrs), PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => { @@ -780,7 +813,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { apply(&ArgAttributes::new()); } match arg.mode { - PassMode::Ignore => {} + PassMode::Ignore(_) => {} PassMode::Direct(ref attrs) | PassMode::Indirect(ref attrs, None) => apply(attrs), PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => { diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index d1cbe1d4dd6..3268af396a2 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -136,22 +136,18 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { let tp_ty = substs.type_at(0); self.const_usize(self.size_of(tp_ty).bytes()) } - func @ "va_start" | func @ "va_end" => { - let va_list = match (tcx.lang_items().va_list(), &result.layout.ty.sty) { - (Some(did), ty::Adt(def, _)) if def.did == did => args[0].immediate(), - (Some(_), _) => self.load(args[0].immediate(), - tcx.data_layout.pointer_align.abi), - (None, _) => bug!("va_list language item must be defined") - }; - let intrinsic = self.cx().get_intrinsic(&format!("llvm.{}", func)); - self.call(intrinsic, &[va_list], None) + "va_start" => { + self.va_start(args[0].immediate()) + } + "va_end" => { + self.va_end(args[0].immediate()) } "va_copy" => { let va_list = match (tcx.lang_items().va_list(), &result.layout.ty.sty) { (Some(did), ty::Adt(def, _)) if def.did == did => args[0].immediate(), (Some(_), _) => self.load(args[0].immediate(), tcx.data_layout.pointer_align.abi), - (None, _) => bug!("va_list language item must be defined") + (None, _) => bug!("`va_list` language item must be defined") }; let intrinsic = self.cx().get_intrinsic(&("llvm.va_copy")); self.call(intrinsic, &[llresult, va_list], None); @@ -722,6 +718,41 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { let expect = self.get_intrinsic(&"llvm.expect.i1"); self.call(expect, &[cond, self.const_bool(expected)], None) } + + fn va_start(&mut self, list: &'ll Value) -> &'ll Value { + let target = &self.cx.tcx.sess.target.target; + let arch = &target.arch; + // A pointer to the architecture specific structure is passed to this + // function. For pointer variants (i686, RISC-V, Windows, etc), we + // should do do nothing, as the address to the pointer is needed. For + // architectures with a architecture specific structure (`Aarch64`, + // `X86_64`, etc), this function should load the structure from the + // address provided. + let va_list = match &**arch { + _ if target.options.is_like_windows => list, + "aarch64" if target.target_os == "ios" => list, + "aarch64" | "x86_64" | "powerpc" => + self.load(list, self.tcx().data_layout.pointer_align.abi), + _ => list, + }; + let intrinsic = self.cx().get_intrinsic("llvm.va_start"); + self.call(intrinsic, &[va_list], None) + } + + fn va_end(&mut self, list: &'ll Value) -> &'ll Value { + let target = &self.cx.tcx.sess.target.target; + let arch = &target.arch; + // See the comment in `va_start` for the purpose of the following. + let va_list = match &**arch { + _ if target.options.is_like_windows => list, + "aarch64" if target.target_os == "ios" => list, + "aarch64" | "x86_64" | "powerpc" => + self.load(list, self.tcx().data_layout.pointer_align.abi), + _ => list, + }; + let intrinsic = self.cx().get_intrinsic("llvm.va_end"); + self.call(intrinsic, &[va_list], None) + } } fn copy_intrinsic( diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs index 4fe6a1f4f4b..7f0cdb9f580 100644 --- a/src/librustc_codegen_llvm/mono_item.rs +++ b/src/librustc_codegen_llvm/mono_item.rs @@ -36,10 +36,10 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn predefine_fn(&self, - instance: Instance<'tcx>, - linkage: Linkage, - visibility: Visibility, - symbol_name: &str) { + instance: Instance<'tcx>, + linkage: Linkage, + visibility: Visibility, + symbol_name: &str) { assert!(!instance.substs.needs_infer() && !instance.substs.has_param_types()); diff --git a/src/librustc_codegen_llvm/va_arg.rs b/src/librustc_codegen_llvm/va_arg.rs index 8719390b51a..7aceaea4510 100644 --- a/src/librustc_codegen_llvm/va_arg.rs +++ b/src/librustc_codegen_llvm/va_arg.rs @@ -109,12 +109,12 @@ pub(super) fn emit_va_arg( Align::from_bytes(4).unwrap(), true) } // Windows Aarch64 - ("aarch4", true) => { + ("aarch64", true) => { emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), false) } // iOS Aarch64 - ("aarch4", _) if target.target_os == "ios" => { + ("aarch64", _) if target.target_os == "ios" => { emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), true) } diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index caca1789fc9..f40aa0cb6d1 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -3,7 +3,7 @@ use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::layout::{self, LayoutOf, HasTyCtxt}; use rustc::mir; use rustc::mir::interpret::EvalErrorKind; -use rustc_target::abi::call::{ArgType, FnType, PassMode}; +use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode}; use rustc_target::spec::abi::Abi; use rustc_mir::monomorphize; use crate::base; @@ -18,7 +18,7 @@ use syntax_pos::Pos; use super::{FunctionCx, LocalRef}; use super::place::PlaceRef; -use super::operand::OperandRef; +use super::operand::{OperandValue, OperandRef}; use super::operand::OperandValue::{Pair, Ref, Immediate}; impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { @@ -232,12 +232,21 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::TerminatorKind::Return => { + if self.fn_ty.variadic { + if let Some(va_list) = self.va_list_ref { + bx.va_end(va_list.llval); + } + } let llval = match self.fn_ty.ret.mode { - PassMode::Ignore | PassMode::Indirect(..) => { + PassMode::Ignore(IgnoreMode::Zst) | PassMode::Indirect(..) => { bx.ret_void(); return; } + PassMode::Ignore(IgnoreMode::CVarArgs) => { + bug!("C variadic arguments should never be the return type"); + } + PassMode::Direct(_) | PassMode::Pair(..) => { let op = self.codegen_consume(&mut bx, &mir::Place::Local(mir::RETURN_PLACE)); @@ -481,7 +490,10 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - let extra_args = &args[sig.inputs().len()..]; + // The "spoofed" `VaList` added to a C-variadic functions signature + // should not be included in the `extra_args` calculation. + let extra_args_start_idx = sig.inputs().len() - if sig.variadic { 1 } else { 0 }; + let extra_args = &args[extra_args_start_idx..]; let extra_args = extra_args.iter().map(|op_arg| { let op_ty = op_arg.ty(self.mir, bx.tcx()); self.monomorphize(&op_ty) @@ -658,7 +670,37 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { (&args[..], None) }; + // Useful determining if the current argument is the "spoofed" `VaList` + let last_arg_idx = if sig.inputs().is_empty() { + None + } else { + Some(sig.inputs().len() - 1) + }; 'make_args: for (i, arg) in first_args.iter().enumerate() { + // If this is a C-variadic function the function signature contains + // an "spoofed" `VaList`. This argument is ignored, but we need to + // populate it with a dummy operand so that the users real arguments + // are not overwritten. + let i = if sig.variadic && last_arg_idx.map(|x| x == i).unwrap_or(false) { + let layout = match tcx.lang_items().va_list() { + Some(did) => bx.cx().layout_of(bx.tcx().type_of(did)), + None => bug!("va_list language item required for C variadics"), + }; + let op = OperandRef { + val: OperandValue::Immediate( + bx.cx().const_undef(bx.cx().immediate_backend_type(layout)) + ), + layout: layout, + }; + self.codegen_argument(&mut bx, op, &mut llargs, &fn_ty.args[i]); + if i + 1 < fn_ty.args.len() { + i + 1 + } else { + break 'make_args + } + } else { + i + }; let mut op = self.codegen_operand(&mut bx, arg); if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) { diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index e1528921a59..95cf8cfe2d0 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -5,7 +5,7 @@ use rustc::mir::{self, Mir}; use rustc::ty::subst::SubstsRef; use rustc::session::config::DebugInfo; use rustc_mir::monomorphize::Instance; -use rustc_target::abi::call::{FnType, PassMode}; +use rustc_target::abi::call::{FnType, PassMode, IgnoreMode}; use crate::base; use crate::debuginfo::{self, VariableAccess, VariableKind, FunctionDebugContext}; use crate::traits::*; @@ -86,6 +86,10 @@ pub struct FunctionCx<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> { /// If this function is being monomorphized, this contains the type substitutions used. param_substs: SubstsRef<'tcx>, + + /// If this function is a C-variadic function, this contains the `PlaceRef` of the + /// "spoofed" `VaList`. + va_list_ref: Option>, } impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { @@ -246,13 +250,18 @@ pub fn codegen_mir<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( assert!(!instance.substs.needs_infer()); instance.substs }, + va_list_ref: None, }; let memory_locals = analyze::non_ssa_locals(&fx); // Allocate variable and temp allocas fx.locals = { - let args = arg_local_refs(&mut bx, &fx, &fx.scopes, &memory_locals); + // FIXME(dlrobertson): This is ugly. Find a better way of getting the `PlaceRef` or + // `LocalRef` from `arg_local_refs` + let mut va_list_ref = None; + let args = arg_local_refs(&mut bx, &fx, &fx.scopes, &memory_locals, &mut va_list_ref); + fx.va_list_ref = va_list_ref; let mut allocate_local = |local| { let decl = &mir.local_decls[local]; @@ -433,6 +442,7 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( debuginfo::MirDebugScope >, memory_locals: &BitSet, + va_list_ref: &mut Option>, ) -> Vec> { let mir = fx.mir; let tcx = fx.cx.tcx(); @@ -447,6 +457,15 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( None }; + // Store the index of the last argument. This is used to + // call va_start on the va_list instead of attempting + // to store_fn_arg. + let last_arg_idx = if fx.fn_ty.args.is_empty() { + None + } else { + Some(fx.fn_ty.args.len() - 1) + }; + mir.args_iter().enumerate().map(|(arg_index, local)| { let arg_decl = &mir.local_decls[local]; @@ -510,9 +529,16 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( // of putting everything in allocas just so we can use llvm.dbg.declare. let local = |op| LocalRef::Operand(Some(op)); match arg.mode { - PassMode::Ignore => { + PassMode::Ignore(IgnoreMode::Zst) => { return local(OperandRef::new_zst(bx.cx(), arg.layout)); } + PassMode::Ignore(IgnoreMode::CVarArgs) => { + let backend_type = bx.cx().immediate_backend_type(arg.layout); + return local(OperandRef { + val: OperandValue::Immediate(bx.cx().const_undef(backend_type)), + layout: arg.layout, + }); + } PassMode::Direct(_) => { let llarg = bx.get_param(bx.llfn(), llarg_idx as c_uint); bx.set_value_name(llarg, &name); @@ -559,9 +585,35 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( indirect_operand.store(bx, tmp); tmp } else { - let tmp = PlaceRef::alloca(bx, arg.layout, &name); - bx.store_fn_arg(arg, &mut llarg_idx, tmp); - tmp + if fx.fn_ty.variadic && last_arg_idx.map(|idx| arg_index == idx).unwrap_or(false) { + let va_list_impl = match arg_decl.ty.ty_adt_def() { + Some(adt) => adt.non_enum_variant(), + None => bug!("`va_list` language item improperly constructed") + }; + match tcx.type_of(va_list_impl.fields[0].did).sty { + ty::Ref(_, ty, _) => { + // If the underlying structure the `VaList` contains is a structure, + // we need to allocate it (e.g., X86_64 on Linux). + let tmp = PlaceRef::alloca(bx, arg.layout, &name); + if let ty::Adt(..) = ty.sty { + let layout = bx.layout_of(ty); + // Create an unnamed allocation for the backing structure + // and store it in the the spoofed `VaList`. + let backing = PlaceRef::alloca(bx, layout, ""); + bx.store(backing.llval, tmp.llval, layout.align.abi); + } + // Call `va_start` on the spoofed `VaList`. + bx.va_start(tmp.llval); + *va_list_ref = Some(tmp); + tmp + } + _ => bug!("improperly constructed `va_list` lang item"), + } + } else { + let tmp = PlaceRef::alloca(bx, arg.layout, &name); + bx.store_fn_arg(arg, &mut llarg_idx, tmp); + tmp + } }; arg_scope.map(|scope| { // Is this a regular argument? diff --git a/src/librustc_codegen_ssa/traits/intrinsic.rs b/src/librustc_codegen_ssa/traits/intrinsic.rs index 3cd0c39d413..cd527898977 100644 --- a/src/librustc_codegen_ssa/traits/intrinsic.rs +++ b/src/librustc_codegen_ssa/traits/intrinsic.rs @@ -20,4 +20,10 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes { fn abort(&mut self); fn assume(&mut self, val: Self::Value); fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value; + /// Trait method used to inject `va_start` on the "spoofed" `VaList` in + /// Rust defined C-variadic functions. + fn va_start(&mut self, val: Self::Value) -> Self::Value; + /// Trait method used to inject `va_end` on the "spoofed" `VaList` before + /// Rust defined C-variadic functions return. + fn va_end(&mut self, val: Self::Value) -> Self::Value; } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index a56c3215f9d..fb279a5d9b8 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -766,8 +766,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let def_id = self.cx.tcx.hir().local_def_id(id); let sig = self.cx.tcx.fn_sig(def_id); let sig = self.cx.tcx.erase_late_bound_regions(&sig); + let inputs = if sig.variadic { + // Don't include the spoofed `VaList` in the functions list + // of inputs. + &sig.inputs()[..sig.inputs().len() - 1] + } else { + &sig.inputs()[..] + }; - for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) { + for (input_ty, input_hir) in inputs.iter().zip(&decl.inputs) { self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty); } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 4202d10aa63..f897795d86f 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1602,10 +1602,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { from_hir_call: bool, ) { debug!("check_call_inputs({:?}, {:?})", sig, args); - if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.variadic) { + // Do not count the `VaList` argument as a "true" argument to + // a C-variadic function. + let inputs = if sig.variadic { + &sig.inputs()[..sig.inputs().len() - 1] + } else { + &sig.inputs()[..] + }; + if args.len() < inputs.len() || (args.len() > inputs.len() && !sig.variadic) { span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); } - for (n, (fn_arg, op_arg)) in sig.inputs().iter().zip(args).enumerate() { + for (n, (fn_arg, op_arg)) in inputs.iter().zip(args).enumerate() { let op_arg_ty = op_arg.ty(mir, self.tcx()); let category = if from_hir_call { ConstraintCategory::CallArgument diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 50a335bf908..222c43de3b7 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -190,6 +190,7 @@ impl Sig for ast::Ty { Ok(replace_text(nested, text)) } ast::TyKind::Never => Ok(text_sig("!".to_owned())), + ast::TyKind::CVarArgs => Ok(text_sig("...".to_owned())), ast::TyKind::Tup(ref ts) => { let mut text = "(".to_owned(); let mut defs = vec![]; diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index 411eb192d90..8ada328a158 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -23,10 +23,18 @@ mod x86_64; mod x86_win64; mod wasm32; +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum IgnoreMode { + /// C-variadic arguments. + CVarArgs, + /// A zero-sized type. + Zst, +} + #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum PassMode { - /// Ignore the argument (useful for empty struct). - Ignore, + /// Ignore the argument (useful for empty structs and C-variadic args). + Ignore(IgnoreMode), /// Pass the argument directly. Direct(ArgAttributes), /// Pass a pair's elements directly in two arguments. @@ -481,7 +489,10 @@ impl<'a, Ty> ArgType<'a, Ty> { } pub fn is_ignore(&self) -> bool { - self.mode == PassMode::Ignore + match self.mode { + PassMode::Ignore(_) => true, + _ => false + } } } diff --git a/src/librustc_target/abi/call/x86.rs b/src/librustc_target/abi/call/x86.rs index 2e809571ab1..6ca3ce88bd6 100644 --- a/src/librustc_target/abi/call/x86.rs +++ b/src/librustc_target/abi/call/x86.rs @@ -88,7 +88,7 @@ pub fn compute_abi_info<'a, Ty, C>(cx: &C, fty: &mut FnType<'a, Ty>, flavor: Fla for arg in &mut fty.args { let attrs = match arg.mode { - PassMode::Ignore | + PassMode::Ignore(_) | PassMode::Indirect(_, None) => continue, PassMode::Direct(ref mut attrs) => attrs, PassMode::Pair(..) | diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 6f3dc8b969c..1d99584eec4 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1822,6 +1822,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { hir::TyKind::Err => { tcx.types.err } + hir::TyKind::CVarArgs(lt) => { + let va_list_did = match tcx.lang_items().va_list() { + Some(did) => did, + None => span_bug!(ast_ty.span, + "`va_list` lang item required for variadics"), + }; + let region = self.ast_region_to_region(<, None); + tcx.type_of(va_list_did).subst(tcx, &[region.into()]) + } }; self.record_ty(ast_ty.hir_id, result_ty, ast_ty.span); diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 7bf7d825406..aeb43635eb7 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -368,17 +368,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .0; let fn_sig = self.normalize_associated_types_in(call_expr.span, &fn_sig); + let inputs = if fn_sig.variadic { + if fn_sig.inputs().len() > 1 { + &fn_sig.inputs()[..fn_sig.inputs().len() - 1] + } else { + span_bug!(call_expr.span, + "C-variadic functions are only valid with one or more fixed arguments"); + } + } else { + &fn_sig.inputs()[..] + }; // Call the generic checker. let expected_arg_tys = self.expected_inputs_for_expected_output( call_expr.span, expected, fn_sig.output(), - fn_sig.inputs(), + inputs, ); self.check_argument_types( call_expr.span, call_expr.span, - fn_sig.inputs(), + inputs, &expected_arg_tys[..], arg_exprs, fn_sig.variadic, diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 3b174b55f2b..924ced2e2a3 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -337,7 +337,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "va_start" | "va_end" => { match mk_va_list_ty() { Some(va_list_ty) => (0, vec![va_list_ty], tcx.mk_unit()), - None => bug!("va_list lang_item must be defined to use va_list intrinsics") + None => bug!("`va_list` language item needed for C-variadic intrinsics") } } @@ -364,14 +364,14 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; (0, vec![tcx.mk_imm_ref(tcx.mk_region(env_region), va_list_ty)], ret_ty) } - None => bug!("va_list lang_item must be defined to use va_list intrinsics") + None => bug!("`va_list` language item needed for C-variadic intrinsics") } } "va_arg" => { match mk_va_list_ty() { Some(va_list_ty) => (1, vec![va_list_ty], param(0)), - None => bug!("va_list lang_item must be defined to use va_list intrinsics") + None => bug!("`va_list` language item needed for C-variadic intrinsics") } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 72abbae231a..53dcc258c69 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1752,7 +1752,6 @@ impl Clean for doctree::Function { pub struct FnDecl { pub inputs: Arguments, pub output: FunctionRetTy, - pub variadic: bool, pub attrs: Attributes, } @@ -1831,7 +1830,6 @@ impl<'a, A: Copy> Clean for (&'a hir::FnDecl, A) FnDecl { inputs: (&self.0.inputs[..], self.1).clean(cx), output: self.0.output.clean(cx), - variadic: self.0.variadic, attrs: Attributes::default() } } @@ -1849,7 +1847,6 @@ impl<'a, 'tcx> Clean for (DefId, ty::PolyFnSig<'tcx>) { FnDecl { output: Return(sig.skip_binder().output().clean(cx)), attrs: Attributes::default(), - variadic: sig.skip_binder().variadic, inputs: Arguments { values: sig.skip_binder().inputs().iter().map(|t| { Argument { @@ -2252,6 +2249,7 @@ pub enum Type { Slice(Box), Array(Box, String), Never, + CVarArgs, Unique(Box), RawPointer(Mutability, Box), BorrowedRef { @@ -2290,6 +2288,7 @@ pub enum PrimitiveType { Reference, Fn, Never, + CVarArgs, } #[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)] @@ -2469,6 +2468,7 @@ impl PrimitiveType { Reference => "reference", Fn => "fn", Never => "never", + CVarArgs => "...", } } @@ -2518,6 +2518,7 @@ impl Clean for hir::Ty { match self.node { TyKind::Never => Never, + TyKind::CVarArgs(_) => CVarArgs, TyKind::Ptr(ref m) => RawPointer(m.mutbl.clean(cx), box m.ty.clean(cx)), TyKind::Rptr(ref l, ref m) => { let lifetime = if l.is_elided() { @@ -3654,6 +3655,7 @@ fn build_deref_target_impls(cx: &DocContext<'_, '_, '_>, Reference => None, Fn => None, Never => None, + CVarArgs => tcx.lang_items().va_list(), }; if let Some(did) = did { if !did.is_local() { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 4463dad1c8a..d204a179ca6 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -609,6 +609,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> primitive_link(f, PrimitiveType::Array, &format!("; {}]", n)) } clean::Never => primitive_link(f, PrimitiveType::Never, "!"), + clean::CVarArgs => primitive_link(f, PrimitiveType::CVarArgs, "..."), clean::RawPointer(m, ref t) => { match **t { clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => { @@ -834,18 +835,10 @@ impl fmt::Display for clean::FunctionRetTy { impl fmt::Display for clean::FnDecl { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.variadic { - if f.alternate() { - write!(f, "({args:#}, ...){arrow:#}", args = self.inputs, arrow = self.output) - } else { - write!(f, "({args}, ...){arrow}", args = self.inputs, arrow = self.output) - } + if f.alternate() { + write!(f, "({args:#}){arrow:#}", args = self.inputs, arrow = self.output) } else { - if f.alternate() { - write!(f, "({args:#}){arrow:#}", args = self.inputs, arrow = self.output) - } else { - write!(f, "({args}){arrow}", args = self.inputs, arrow = self.output) - } + write!(f, "({args}){arrow}", args = self.inputs, arrow = self.output) } } } @@ -907,12 +900,7 @@ impl<'a> fmt::Display for Function<'a> { } } - let mut args_plain = format!("({})", args_plain); - - if decl.variadic { - args.push_str(",
..."); - args_plain.push_str(", ..."); - } + let args_plain = format!("({})", args_plain); let output = if let hir::IsAsync::Async = asyncness { Cow::Owned(decl.sugared_async_return_type()) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 9c4945d74db..5bae00b9cb8 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1643,6 +1643,8 @@ pub enum TyKind { Mac(Mac), /// Placeholder for a kind that has failed to be defined. Err, + /// Placeholder for a `va_list`. + CVarArgs, } impl TyKind { diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 86849f580d0..8efc4689cac 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -401,7 +401,8 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { let Ty { id, node, span } = ty.deref_mut(); vis.visit_id(id); match node { - TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | TyKind::Never => {} + TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | + TyKind::Never | TyKind::CVarArgs => {} TyKind::Slice(ty) => vis.visit_ty(ty), TyKind::Ptr(mt) => vis.visit_mt(mt), TyKind::Rptr(lt, mt) => { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7e900dfeb1e..b58091b57da 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1543,7 +1543,7 @@ impl<'a> Parser<'a> { // definition... // We don't allow argument names to be left off in edition 2018. - p.parse_arg_general(p.span.rust_2018(), true) + p.parse_arg_general(p.span.rust_2018(), true, false) })?; generics.where_clause = self.parse_where_clause()?; @@ -1613,7 +1613,7 @@ impl<'a> Parser<'a> { /// Parses an optional return type `[ -> TY ]` in a function declaration. fn parse_ret_ty(&mut self, allow_plus: bool) -> PResult<'a, FunctionRetTy> { if self.eat(&token::RArrow) { - Ok(FunctionRetTy::Ty(self.parse_ty_common(allow_plus, true)?)) + Ok(FunctionRetTy::Ty(self.parse_ty_common(allow_plus, true, false)?)) } else { Ok(FunctionRetTy::Default(self.span.shrink_to_lo())) } @@ -1621,7 +1621,7 @@ impl<'a> Parser<'a> { /// Parses a type. pub fn parse_ty(&mut self) -> PResult<'a, P> { - self.parse_ty_common(true, true) + self.parse_ty_common(true, true, false) } /// Parses a type in restricted contexts where `+` is not permitted. @@ -1631,11 +1631,11 @@ impl<'a> Parser<'a> { /// Example 2: `value1 as TYPE + value2` /// `+` is prohibited to avoid interactions with expression grammar. fn parse_ty_no_plus(&mut self) -> PResult<'a, P> { - self.parse_ty_common(false, true) + self.parse_ty_common(false, true, false) } - fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool) - -> PResult<'a, P> { + fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool, + allow_variadic: bool) -> PResult<'a, P> { maybe_whole!(self, NtTy, |x| x); let lo = self.span; @@ -1772,6 +1772,15 @@ impl<'a> Parser<'a> { TyKind::Path(None, path) } } + } else if self.check(&token::DotDotDot) { + if allow_variadic { + self.eat(&token::DotDotDot); + TyKind::CVarArgs + } else { + return Err(self.fatal( + "only foreign functions are allowed to be variadic" + )); + } } else { let msg = format!("expected type, found {}", self.this_token_descr()); return Err(self.fatal(&msg)); @@ -1959,7 +1968,8 @@ impl<'a> Parser<'a> { } /// This version of parse arg doesn't necessarily require identifier names. - fn parse_arg_general(&mut self, require_name: bool, is_trait_item: bool) -> PResult<'a, Arg> { + fn parse_arg_general(&mut self, require_name: bool, is_trait_item: bool, + allow_variadic: bool) -> PResult<'a, Arg> { maybe_whole!(self, NtArg, |x| x); if let Ok(Some(_)) = self.parse_self_arg() { @@ -2008,12 +2018,12 @@ impl<'a> Parser<'a> { } self.eat_incorrect_doc_comment("a method argument's type"); - (pat, self.parse_ty()?) + (pat, self.parse_ty_common(true, true, allow_variadic)?) } else { debug!("parse_arg_general ident_to_pat"); let parser_snapshot_before_ty = self.clone(); self.eat_incorrect_doc_comment("a method argument's type"); - let mut ty = self.parse_ty(); + let mut ty = self.parse_ty_common(true, true, allow_variadic); if ty.is_ok() && self.token != token::Comma && self.token != token::CloseDelim(token::Paren) { // This wasn't actually a type, but a pattern looking like a type, @@ -2032,6 +2042,11 @@ impl<'a> Parser<'a> { (pat, ty) } Err(mut err) => { + // If this is a variadic argument and we hit an error, return the + // error. + if self.token == token::DotDotDot { + return Err(err); + } // Recover from attempting to parse the argument as a type without pattern. err.cancel(); mem::replace(self, parser_snapshot_before_ty); @@ -2068,7 +2083,7 @@ impl<'a> Parser<'a> { /// Parses a single function argument. crate fn parse_arg(&mut self) -> PResult<'a, Arg> { - self.parse_arg_general(true, false) + self.parse_arg_general(true, false, false) } /// Parses an argument in a lambda header (e.g., `|arg, arg|`). @@ -2406,7 +2421,7 @@ impl<'a> Parser<'a> { } let span = lo.to(self.prev_span); let output = if self.eat(&token::RArrow) { - Some(self.parse_ty_common(false, false)?) + Some(self.parse_ty_common(false, false, false)?) } else { None }; @@ -6118,44 +6133,38 @@ impl<'a> Parser<'a> { &token::CloseDelim(token::Paren), SeqSep::trailing_allowed(token::Comma), |p| { - if p.token == token::DotDotDot { - p.bump(); - variadic = true; - if allow_variadic { - if p.token != token::CloseDelim(token::Paren) { - let span = p.span; - p.span_err(span, - "`...` must be last in argument list for variadic function"); - } - Ok(None) - } else { - let span = p.prev_span; - if p.token == token::CloseDelim(token::Paren) { - // continue parsing to present any further errors - p.struct_span_err( - span, - "only foreign functions are allowed to be variadic" - ).emit(); - Ok(Some(dummy_arg(span))) - } else { - // this function definition looks beyond recovery, stop parsing - p.span_err(span, - "only foreign functions are allowed to be variadic"); - Ok(None) - } - } + // If the argument is a C-variadic argument we should not + // enforce named arguments. + let enforce_named_args = if p.token == token::DotDotDot { + false } else { - match p.parse_arg_general(named_args, false) { - Ok(arg) => Ok(Some(arg)), - Err(mut e) => { - e.emit(); - let lo = p.prev_span; - // Skip every token until next possible arg or end. - p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]); - // Create a placeholder argument for proper arg count (#34264). - let span = lo.to(p.prev_span); - Ok(Some(dummy_arg(span))) + named_args + }; + match p.parse_arg_general(enforce_named_args, false, + allow_variadic) { + Ok(arg) => { + if let TyKind::CVarArgs = arg.ty.node { + variadic = true; + if p.token != token::CloseDelim(token::Paren) { + let span = p.span; + p.span_err(span, + "`...` must be last in argument list in variadic function"); + Ok(None) + } else { + Ok(Some(arg)) + } + } else { + Ok(Some(arg)) } + }, + Err(mut e) => { + e.emit(); + let lo = p.prev_span; + // Skip every token until next possible arg or end. + p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]); + // Create a placeholder argument for proper arg count (issue #34264). + let span = lo.to(p.prev_span); + Ok(Some(dummy_arg(span))) } } } @@ -6389,7 +6398,8 @@ impl<'a> Parser<'a> { abi: Abi) -> PResult<'a, ItemInfo> { let (ident, mut generics) = self.parse_fn_header()?; - let decl = self.parse_fn_decl(false)?; + let allow_variadic = abi == Abi::C && unsafety == Unsafety::Unsafe; + let decl = self.parse_fn_decl(allow_variadic)?; generics.where_clause = self.parse_where_clause()?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; let header = FnHeader { unsafety, asyncness, constness, abi }; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index dcf9815f6d1..b3964d0ce9c 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1118,6 +1118,9 @@ impl<'a> State<'a> { ast::TyKind::Mac(ref m) => { self.print_mac(m)?; } + ast::TyKind::CVarArgs => { + self.s.word("...")?; + } } self.end() } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index a002394c710..dd9f4f74d9e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -315,7 +315,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { walk_list!(visitor, visit_lifetime, opt_lifetime); visitor.visit_ty(&mutable_type.ty) } - TyKind::Never => {}, + TyKind::Never | TyKind::CVarArgs => {} TyKind::Tup(ref tuple_element_types) => { walk_list!(visitor, visit_ty, tuple_element_types); } diff --git a/src/test/codegen/c-variadic.rs b/src/test/codegen/c-variadic.rs new file mode 100644 index 00000000000..09c18ed90b2 --- /dev/null +++ b/src/test/codegen/c-variadic.rs @@ -0,0 +1,69 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(c_variadic)] +#![no_std] +use core::ffi::VaList; + +extern "C" { + fn foreign_c_variadic_0(_: i32, ...); + fn foreign_c_variadic_1(_: VaList, ...); +} + +pub unsafe extern "C" fn use_foreign_c_variadic_0() { + // Ensure that we correctly call foreign C-variadic functions. + // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0) + foreign_c_variadic_0(0); + // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0, i32 42) + foreign_c_variadic_0(0, 42i32); + // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0, i32 42, i32 1024) + foreign_c_variadic_0(0, 42i32, 1024i32); + // CHECK: invoke void (i32, ...) @foreign_c_variadic_0(i32 0, i32 42, i32 1024, i32 0) + foreign_c_variadic_0(0, 42i32, 1024i32, 0i32); +} + +// Ensure that we do not remove the `va_list` passed to the foreign function when +// removing the "spoofed" `VaList` that is used by Rust defined C-variadics. +pub unsafe extern "C" fn use_foreign_c_variadic_1_0(ap: VaList) { + // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap) + foreign_c_variadic_1(ap); +} + +pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) { + // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, i32 42) + foreign_c_variadic_1(ap, 42i32); +} +pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) { + // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, i32 2, i32 42) + foreign_c_variadic_1(ap, 2i32, 42i32); +} + +pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) { + // CHECK: invoke void ({{.*}}*, ...) @foreign_c_variadic_1({{.*}} %ap, i32 2, i32 42, i32 0) + foreign_c_variadic_1(ap, 2i32, 42i32, 0i32); +} + +// Ensure that `va_start` and `va_end` are properly injected. +#[no_mangle] +pub unsafe extern "C" fn c_variadic(n: i32, mut ap: ...) -> i32 { + // CHECK: call void @llvm.va_start + let mut sum = 0; + for _ in 0..n { + sum += ap.arg::(); + } + sum + // CHECK: call void @llvm.va_end +} + +// Ensure that we generate the correct `call` signature when calling a Rust +// defined C-variadic. +pub unsafe fn test_c_variadic_call() { + // CHECK: call i32 (i32, ...) @c_variadic(i32 0) + c_variadic(0); + // CHECK: call i32 (i32, ...) @c_variadic(i32 0, i32 42) + c_variadic(0, 42i32); + // CHECK: call i32 (i32, ...) @c_variadic(i32 0, i32 42, i32 1024) + c_variadic(0, 42i32, 1024i32); + // CHECK: call i32 (i32, ...) @c_variadic(i32 0, i32 42, i32 1024, i32 0) + c_variadic(0, 42i32, 1024i32, 0i32); +} diff --git a/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs b/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs index d55aac1e40f..96a238afaec 100644 --- a/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs +++ b/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/checkrust.rs @@ -18,8 +18,10 @@ macro_rules! continue_if { unsafe fn compare_c_str(ptr: *const c_char, val: &str) -> bool { let cstr0 = CStr::from_ptr(ptr); - let cstr1 = CString::new(val).unwrap(); - &*cstr1 == cstr0 + match CString::new(val) { + Ok(cstr1) => &*cstr1 == cstr0, + Err(_) => false, + } } #[no_mangle] @@ -68,3 +70,24 @@ pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize { } }) } + +#[no_mangle] +pub unsafe extern "C" fn check_varargs_0(_: c_int, mut ap: ...) -> usize { + continue_if!(ap.arg::() == 42); + continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Hello, World!")); + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize { + continue_if!(ap.arg::().floor() == 3.14f64.floor()); + continue_if!(ap.arg::() == 12); + continue_if!(ap.arg::() == 'A' as c_char); + continue_if!(ap.arg::() == 1); + 0 +} + +#[no_mangle] +pub unsafe extern "C" fn check_varargs_2(_: c_int, mut ap: ...) -> usize { + 0 +} diff --git a/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/test.c b/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/test.c index 95cf0ef46ca..91b060dce26 100644 --- a/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/test.c +++ b/src/test/run-make-fulldeps/c-link-to-rust-va-list-fn/test.c @@ -8,6 +8,9 @@ extern size_t check_list_0(va_list ap); extern size_t check_list_1(va_list ap); extern size_t check_list_2(va_list ap); extern size_t check_list_copy_0(va_list ap); +extern size_t check_varargs_0(int fixed, ...); +extern size_t check_varargs_1(int fixed, ...); +extern size_t check_varargs_2(int fixed, ...); int test_rust(size_t (*fn)(va_list), ...) { size_t ret = 0; @@ -26,5 +29,12 @@ int main(int argc, char* argv[]) { assert(test_rust(check_list_2, 3.14, 12l, 'a', 6.28, "Hello", 42, "World") == 0); assert(test_rust(check_list_copy_0, 6.28, 16, 'A', "Skip Me!", "Correct") == 0); + + assert(check_varargs_0(0, 42, "Hello, World!") == 0); + + assert(check_varargs_1(0, 3.14, 12l, 'A', 0x1LL) == 0); + + assert(check_varargs_2(0, "All", "of", "these", "are", "ignored", ".") == 0); + return 0; } diff --git a/src/test/rustdoc/variadic.rs b/src/test/rustdoc/variadic.rs index bd8f1775b3d..5af2aea21fc 100644 --- a/src/test/rustdoc/variadic.rs +++ b/src/test/rustdoc/variadic.rs @@ -1,4 +1,4 @@ extern "C" { - // @has variadic/fn.foo.html //pre 'pub unsafe extern "C" fn foo(x: i32, ...)' + // @has variadic/fn.foo.html //pre 'pub unsafe extern "C" fn foo(x: i32, _: ...)' pub fn foo(x: i32, ...); } diff --git a/src/test/ui/c-variadic/variadic-ffi-1.rs b/src/test/ui/c-variadic/variadic-ffi-1.rs new file mode 100644 index 00000000000..61b2ad4bed5 --- /dev/null +++ b/src/test/ui/c-variadic/variadic-ffi-1.rs @@ -0,0 +1,31 @@ +// ignore-arm stdcall isn't supported +// ignore-aarch64 stdcall isn't supported + +extern "stdcall" { + fn printf(_: *const u8, ...); //~ ERROR: variadic function must have C or cdecl calling +} + +extern { + fn foo(f: isize, x: u8, ...); +} + +extern "C" fn bar(f: isize, x: u8) {} + +fn main() { + // errors below are no longer checked because error above aborts + // compilation; see variadic-ffi-3.rs for corresponding test. + unsafe { + foo(); + foo(1); + + let x: unsafe extern "C" fn(f: isize, x: u8) = foo; + let y: extern "C" fn(f: isize, x: u8, ...) = bar; + + foo(1, 2, 3f32); + foo(1, 2, true); + foo(1, 2, 1i8); + foo(1, 2, 1u8); + foo(1, 2, 1i16); + foo(1, 2, 1u16); + } +} diff --git a/src/test/ui/c-variadic/variadic-ffi-1.stderr b/src/test/ui/c-variadic/variadic-ffi-1.stderr new file mode 100644 index 00000000000..52d7394d6af --- /dev/null +++ b/src/test/ui/c-variadic/variadic-ffi-1.stderr @@ -0,0 +1,9 @@ +error[E0045]: variadic function must have C or cdecl calling convention + --> $DIR/variadic-ffi-1.rs:5:5 + | +LL | fn printf(_: *const u8, ...); //~ ERROR: variadic function must have C or cdecl calling + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variadics require C or cdecl calling convention + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0045`. diff --git a/src/test/ui/c-variadic/variadic-ffi-2.rs b/src/test/ui/c-variadic/variadic-ffi-2.rs new file mode 100644 index 00000000000..224ac16f458 --- /dev/null +++ b/src/test/ui/c-variadic/variadic-ffi-2.rs @@ -0,0 +1,8 @@ +// ignore-arm stdcall isn't supported + +fn baz(f: extern "stdcall" fn(usize, ...)) { + //~^ ERROR: variadic function must have C or cdecl calling convention + f(22, 44); +} + +fn main() {} diff --git a/src/test/ui/c-variadic/variadic-ffi-2.stderr b/src/test/ui/c-variadic/variadic-ffi-2.stderr new file mode 100644 index 00000000000..cb2a9f874b7 --- /dev/null +++ b/src/test/ui/c-variadic/variadic-ffi-2.stderr @@ -0,0 +1,9 @@ +error[E0045]: variadic function must have C or cdecl calling convention + --> $DIR/variadic-ffi-2.rs:3:11 + | +LL | fn baz(f: extern "stdcall" fn(usize, ...)) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variadics require C or cdecl calling convention + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0045`. diff --git a/src/test/ui/c-variadic/variadic-ffi-3.rs b/src/test/ui/c-variadic/variadic-ffi-3.rs new file mode 100644 index 00000000000..c02d1f54e56 --- /dev/null +++ b/src/test/ui/c-variadic/variadic-ffi-3.rs @@ -0,0 +1,29 @@ +extern { + fn foo(f: isize, x: u8, ...); + //~^ defined here + //~| defined here +} + +extern "C" fn bar(f: isize, x: u8) {} + +fn main() { + unsafe { + foo(); //~ ERROR: this function takes at least 2 parameters but 0 parameters were supplied + foo(1); //~ ERROR: this function takes at least 2 parameters but 1 parameter was supplied + + let x: unsafe extern "C" fn(f: isize, x: u8) = foo; + //~^ ERROR: mismatched types + //~| expected type `unsafe extern "C" fn(isize, u8)` + + let y: extern "C" fn(f: isize, x: u8, ...) = bar; + //~^ ERROR: mismatched types + //~| expected type `for<'r> extern "C" fn(isize, u8, std::ffi::VaList<'r>, ...)` + + foo(1, 2, 3f32); //~ ERROR can't pass `f32` to variadic function + foo(1, 2, true); //~ ERROR can't pass `bool` to variadic function + foo(1, 2, 1i8); //~ ERROR can't pass `i8` to variadic function + foo(1, 2, 1u8); //~ ERROR can't pass `u8` to variadic function + foo(1, 2, 1i16); //~ ERROR can't pass `i16` to variadic function + foo(1, 2, 1u16); //~ ERROR can't pass `u16` to variadic function + } +} diff --git a/src/test/ui/c-variadic/variadic-ffi-3.stderr b/src/test/ui/c-variadic/variadic-ffi-3.stderr new file mode 100644 index 00000000000..82e3c6cd06f --- /dev/null +++ b/src/test/ui/c-variadic/variadic-ffi-3.stderr @@ -0,0 +1,76 @@ +error[E0060]: this function takes at least 2 parameters but 0 parameters were supplied + --> $DIR/variadic-ffi-3.rs:11:9 + | +LL | fn foo(f: isize, x: u8, ...); + | ----------------------------- defined here +... +LL | foo(); //~ ERROR: this function takes at least 2 parameters but 0 parameters were supplied + | ^^^^^ expected at least 2 parameters + +error[E0060]: this function takes at least 2 parameters but 1 parameter was supplied + --> $DIR/variadic-ffi-3.rs:12:9 + | +LL | fn foo(f: isize, x: u8, ...); + | ----------------------------- defined here +... +LL | foo(1); //~ ERROR: this function takes at least 2 parameters but 1 parameter was supplied + | ^^^^^^ expected at least 2 parameters + +error[E0308]: mismatched types + --> $DIR/variadic-ffi-3.rs:14:56 + | +LL | let x: unsafe extern "C" fn(f: isize, x: u8) = foo; + | ^^^ expected non-variadic fn, found variadic function + | + = note: expected type `unsafe extern "C" fn(isize, u8)` + found type `for<'r> unsafe extern "C" fn(isize, u8, std::ffi::VaList<'r>, ...) {foo}` + +error[E0308]: mismatched types + --> $DIR/variadic-ffi-3.rs:18:54 + | +LL | let y: extern "C" fn(f: isize, x: u8, ...) = bar; + | ^^^ expected variadic fn, found non-variadic function + | + = note: expected type `for<'r> extern "C" fn(isize, u8, std::ffi::VaList<'r>, ...)` + found type `extern "C" fn(isize, u8) {bar}` + +error[E0617]: can't pass `f32` to variadic function + --> $DIR/variadic-ffi-3.rs:22:19 + | +LL | foo(1, 2, 3f32); //~ ERROR can't pass `f32` to variadic function + | ^^^^ help: cast the value to `c_double`: `3f32 as c_double` + +error[E0617]: can't pass `bool` to variadic function + --> $DIR/variadic-ffi-3.rs:23:19 + | +LL | foo(1, 2, true); //~ ERROR can't pass `bool` to variadic function + | ^^^^ help: cast the value to `c_int`: `true as c_int` + +error[E0617]: can't pass `i8` to variadic function + --> $DIR/variadic-ffi-3.rs:24:19 + | +LL | foo(1, 2, 1i8); //~ ERROR can't pass `i8` to variadic function + | ^^^ help: cast the value to `c_int`: `1i8 as c_int` + +error[E0617]: can't pass `u8` to variadic function + --> $DIR/variadic-ffi-3.rs:25:19 + | +LL | foo(1, 2, 1u8); //~ ERROR can't pass `u8` to variadic function + | ^^^ help: cast the value to `c_uint`: `1u8 as c_uint` + +error[E0617]: can't pass `i16` to variadic function + --> $DIR/variadic-ffi-3.rs:26:19 + | +LL | foo(1, 2, 1i16); //~ ERROR can't pass `i16` to variadic function + | ^^^^ help: cast the value to `c_int`: `1i16 as c_int` + +error[E0617]: can't pass `u16` to variadic function + --> $DIR/variadic-ffi-3.rs:27:19 + | +LL | foo(1, 2, 1u16); //~ ERROR can't pass `u16` to variadic function + | ^^^^ help: cast the value to `c_uint`: `1u16 as c_uint` + +error: aborting due to 10 previous errors + +Some errors occurred: E0060, E0308, E0617. +For more information about an error, try `rustc --explain E0060`. diff --git a/src/test/ui/c-variadic/variadic-ffi-4.rs b/src/test/ui/c-variadic/variadic-ffi-4.rs new file mode 100644 index 00000000000..9101be56456 --- /dev/null +++ b/src/test/ui/c-variadic/variadic-ffi-4.rs @@ -0,0 +1,29 @@ +#![crate_type="lib"] +#![no_std] +#![feature(c_variadic)] + +use core::ffi::VaList; + +pub unsafe extern "C" fn no_escape0<'a>(_: usize, ap: ...) -> VaList<'a> { + ap //~ ERROR: explicit lifetime required +} + +pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> { + ap //~ ERROR: explicit lifetime required +} + +pub unsafe extern "C" fn no_escape2(_: usize, ap: ...) { + let _ = ap.copy(|ap| { ap }); //~ ERROR: cannot infer an appropriate lifetime +} + +pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + *ap0 = ap1; //~ ERROR: mismatched types +} + +pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { + ap0 = &mut ap1; + //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long + //~^^ ERROR: mismatched types + //~^^^ ERROR: mismatched types + //~^^^^ ERROR: cannot infer an appropriate lifetime +} diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr new file mode 100644 index 00000000000..1d752be065c --- /dev/null +++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr @@ -0,0 +1,198 @@ +error[E0621]: explicit lifetime required in the type of `ap` + --> $DIR/variadic-ffi-4.rs:8:5 + | +LL | pub unsafe extern "C" fn no_escape0<'a>(_: usize, ap: ...) -> VaList<'a> { + | --- help: add explicit lifetime `'a` to the type of `ap`: `core::ffi::VaList<'a>` +LL | ap //~ ERROR: explicit lifetime required + | ^^ lifetime `'a` required + +error[E0621]: explicit lifetime required in the type of `ap` + --> $DIR/variadic-ffi-4.rs:12:5 + | +LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> { + | --- help: add explicit lifetime `'static` to the type of `ap`: `core::ffi::VaList<'static>` +LL | ap //~ ERROR: explicit lifetime required + | ^^ lifetime `'static` required + +error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements + --> $DIR/variadic-ffi-4.rs:16:28 + | +LL | let _ = ap.copy(|ap| { ap }); //~ ERROR: cannot infer an appropriate lifetime + | ^^ + | +note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 16:21... + --> $DIR/variadic-ffi-4.rs:16:21 + | +LL | let _ = ap.copy(|ap| { ap }); //~ ERROR: cannot infer an appropriate lifetime + | ^^^^^^^^^^^ + = note: ...so that the expression is assignable: + expected core::ffi::VaList<'_> + found core::ffi::VaList<'_> +note: but, the lifetime must be valid for the method call at 16:13... + --> $DIR/variadic-ffi-4.rs:16:13 + | +LL | let _ = ap.copy(|ap| { ap }); //~ ERROR: cannot infer an appropriate lifetime + | ^^^^^^^^^^^^^^^^^^^^ +note: ...so type `core::ffi::VaList<'_>` of expression is valid during the expression + --> $DIR/variadic-ffi-4.rs:16:13 + | +LL | let _ = ap.copy(|ap| { ap }); //~ ERROR: cannot infer an appropriate lifetime + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/variadic-ffi-4.rs:20:12 + | +LL | *ap0 = ap1; //~ ERROR: mismatched types + | ^^^ lifetime mismatch + | + = note: expected type `core::ffi::VaList<'_>` + found type `core::ffi::VaList<'_>` +note: the anonymous lifetime #3 defined on the function body at 19:1... + --> $DIR/variadic-ffi-4.rs:19:1 + | +LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) { +LL | | *ap0 = ap1; //~ ERROR: mismatched types +LL | | } + | |_^ +note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 19:1 + --> $DIR/variadic-ffi-4.rs:19:1 + | +LL | / pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaList, mut ap1: ...) { +LL | | *ap0 = ap1; //~ ERROR: mismatched types +LL | | } + | |_^ + +error[E0490]: a value of type `core::ffi::VaList<'_>` is borrowed for too long + --> $DIR/variadic-ffi-4.rs:24:11 + | +LL | ap0 = &mut ap1; + | ^^^^^^^^ + | +note: the type is valid for the anonymous lifetime #1 defined on the function body at 23:1 + --> $DIR/variadic-ffi-4.rs:23:1 + | +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | | ap0 = &mut ap1; +LL | | //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long +LL | | //~^^ ERROR: mismatched types +LL | | //~^^^ ERROR: mismatched types +LL | | //~^^^^ ERROR: cannot infer an appropriate lifetime +LL | | } + | |_^ +note: but the borrow lasts for the anonymous lifetime #3 defined on the function body at 23:1 + --> $DIR/variadic-ffi-4.rs:23:1 + | +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | | ap0 = &mut ap1; +LL | | //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long +LL | | //~^^ ERROR: mismatched types +LL | | //~^^^ ERROR: mismatched types +LL | | //~^^^^ ERROR: cannot infer an appropriate lifetime +LL | | } + | |_^ + +error[E0308]: mismatched types + --> $DIR/variadic-ffi-4.rs:24:11 + | +LL | ap0 = &mut ap1; + | ^^^^^^^^ lifetime mismatch + | + = note: expected type `&mut core::ffi::VaList<'_>` + found type `&mut core::ffi::VaList<'_>` +note: the anonymous lifetime #3 defined on the function body at 23:1... + --> $DIR/variadic-ffi-4.rs:23:1 + | +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | | ap0 = &mut ap1; +LL | | //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long +LL | | //~^^ ERROR: mismatched types +LL | | //~^^^ ERROR: mismatched types +LL | | //~^^^^ ERROR: cannot infer an appropriate lifetime +LL | | } + | |_^ +note: ...does not necessarily outlive the anonymous lifetime #2 defined on the function body at 23:1 + --> $DIR/variadic-ffi-4.rs:23:1 + | +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | | ap0 = &mut ap1; +LL | | //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long +LL | | //~^^ ERROR: mismatched types +LL | | //~^^^ ERROR: mismatched types +LL | | //~^^^^ ERROR: cannot infer an appropriate lifetime +LL | | } + | |_^ + +error[E0308]: mismatched types + --> $DIR/variadic-ffi-4.rs:24:11 + | +LL | ap0 = &mut ap1; + | ^^^^^^^^ lifetime mismatch + | + = note: expected type `&mut core::ffi::VaList<'_>` + found type `&mut core::ffi::VaList<'_>` +note: the anonymous lifetime #2 defined on the function body at 23:1... + --> $DIR/variadic-ffi-4.rs:23:1 + | +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | | ap0 = &mut ap1; +LL | | //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long +LL | | //~^^ ERROR: mismatched types +LL | | //~^^^ ERROR: mismatched types +LL | | //~^^^^ ERROR: cannot infer an appropriate lifetime +LL | | } + | |_^ +note: ...does not necessarily outlive the anonymous lifetime #3 defined on the function body at 23:1 + --> $DIR/variadic-ffi-4.rs:23:1 + | +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | | ap0 = &mut ap1; +LL | | //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long +LL | | //~^^ ERROR: mismatched types +LL | | //~^^^ ERROR: mismatched types +LL | | //~^^^^ ERROR: cannot infer an appropriate lifetime +LL | | } + | |_^ + +error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements + --> $DIR/variadic-ffi-4.rs:24:11 + | +LL | ap0 = &mut ap1; + | ^^^^^^^^ + | +note: first, the lifetime cannot outlive the anonymous lifetime #3 defined on the function body at 23:1... + --> $DIR/variadic-ffi-4.rs:23:1 + | +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | | ap0 = &mut ap1; +LL | | //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long +LL | | //~^^ ERROR: mismatched types +LL | | //~^^^ ERROR: mismatched types +LL | | //~^^^^ ERROR: cannot infer an appropriate lifetime +LL | | } + | |_^ +note: ...so that the type `core::ffi::VaList<'_>` is not borrowed for too long + --> $DIR/variadic-ffi-4.rs:24:11 + | +LL | ap0 = &mut ap1; + | ^^^^^^^^ +note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the function body at 23:1... + --> $DIR/variadic-ffi-4.rs:23:1 + | +LL | / pub unsafe extern "C" fn no_escape4(_: usize, ap0: &mut VaList, mut ap1: ...) { +LL | | ap0 = &mut ap1; +LL | | //~^ ERROR: a value of type `core::ffi::VaList<'_>` is borrowed for too long +LL | | //~^^ ERROR: mismatched types +LL | | //~^^^ ERROR: mismatched types +LL | | //~^^^^ ERROR: cannot infer an appropriate lifetime +LL | | } + | |_^ +note: ...so that reference does not outlive borrowed content + --> $DIR/variadic-ffi-4.rs:24:11 + | +LL | ap0 = &mut ap1; + | ^^^^^^^^ + +error: aborting due to 8 previous errors + +Some errors occurred: E0308, E0490, E0495, E0621. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/c-variadic/variadic-ffi-5.rs b/src/test/ui/c-variadic/variadic-ffi-5.rs new file mode 100644 index 00000000000..d96482ff4d1 --- /dev/null +++ b/src/test/ui/c-variadic/variadic-ffi-5.rs @@ -0,0 +1,31 @@ +#![crate_type="lib"] +#![no_std] +#![feature(c_variadic)] +// The tests in this file are similar to that of variadic-ffi-4, but this +// one enables nll. +#![feature(nll)] + +use core::ffi::VaList; + +pub unsafe extern "C" fn no_escape0<'a>(_: usize, ap: ...) -> VaList<'a> { + ap //~ ERROR: explicit lifetime required +} + +pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> { + ap //~ ERROR: explicit lifetime required +} + +pub unsafe extern "C" fn no_escape2(_: usize, ap: ...) { + let _ = ap.copy(|ap| { ap }); //~ ERROR: lifetime may not live long enough +} + +pub unsafe extern "C" fn no_escape3(_: usize, ap0: &mut VaList, mut ap1: ...) { + *ap0 = ap1; //~ ERROR: lifetime may not live long enough +} + +pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + ap0 = &mut ap1; + //~^ ERROR: lifetime may not live long enough + //~^^ ERROR: lifetime may not live long enough + //~^^^ ERROR: `ap1` does not live long enough +} diff --git a/src/test/ui/c-variadic/variadic-ffi-5.stderr b/src/test/ui/c-variadic/variadic-ffi-5.stderr new file mode 100644 index 00000000000..2d452872baf --- /dev/null +++ b/src/test/ui/c-variadic/variadic-ffi-5.stderr @@ -0,0 +1,73 @@ +error[E0621]: explicit lifetime required in the type of `ap` + --> $DIR/variadic-ffi-5.rs:11:5 + | +LL | pub unsafe extern "C" fn no_escape0<'a>(_: usize, ap: ...) -> VaList<'a> { + | --- help: add explicit lifetime `'a` to the type of `ap`: `core::ffi::VaList<'a>` +LL | ap //~ ERROR: explicit lifetime required + | ^^ lifetime `'a` required + +error[E0621]: explicit lifetime required in the type of `ap` + --> $DIR/variadic-ffi-5.rs:15:5 + | +LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaList<'static> { + | --- help: add explicit lifetime `'static` to the type of `ap`: `core::ffi::VaList<'static>` +LL | ap //~ ERROR: explicit lifetime required + | ^^ lifetime `'static` required + +error: lifetime may not live long enough + --> $DIR/variadic-ffi-5.rs:19:28 + | +LL | let _ = ap.copy(|ap| { ap }); //~ ERROR: lifetime may not live long enough + | --- ^^ returning this value requires that `'1` must outlive `'2` + | | | + | | return type of closure is core::ffi::VaList<'2> + | has type `core::ffi::VaList<'1>` + +error: lifetime may not live long enough + --> $DIR/variadic-ffi-5.rs:23:5 + | +LL | pub unsafe extern "C" fn no_escape3(_: usize, ap0: &mut VaList, mut ap1: ...) { + | --- ------- has type `core::ffi::VaList<'1>` + | | + | has type `&mut core::ffi::VaList<'2>` +LL | *ap0 = ap1; //~ ERROR: lifetime may not live long enough + | ^^^^^^^^^^ assignment requires that `'1` must outlive `'2` + +error: lifetime may not live long enough + --> $DIR/variadic-ffi-5.rs:27:5 + | +LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + | ------- ------- has type `core::ffi::VaList<'2>` + | | + | has type `&mut core::ffi::VaList<'1>` +LL | ap0 = &mut ap1; + | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` + +error: lifetime may not live long enough + --> $DIR/variadic-ffi-5.rs:27:5 + | +LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + | ------- ------- has type `core::ffi::VaList<'1>` + | | + | has type `&mut core::ffi::VaList<'2>` +LL | ap0 = &mut ap1; + | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` + +error[E0597]: `ap1` does not live long enough + --> $DIR/variadic-ffi-5.rs:27:11 + | +LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { + | - let's call the lifetime of this reference `'1` +LL | ap0 = &mut ap1; + | ------^^^^^^^^ + | | | + | | borrowed value does not live long enough + | assignment requires that `ap1` is borrowed for `'1` +... +LL | } + | - `ap1` dropped here while still borrowed + +error: aborting due to 7 previous errors + +Some errors occurred: E0597, E0621. +For more information about an error, try `rustc --explain E0597`. diff --git a/src/test/ui/c-variadic/variadic-ffi-6.rs b/src/test/ui/c-variadic/variadic-ffi-6.rs new file mode 100644 index 00000000000..9b5293fad3b --- /dev/null +++ b/src/test/ui/c-variadic/variadic-ffi-6.rs @@ -0,0 +1,12 @@ +#![crate_type="lib"] + +pub unsafe extern "C" fn use_vararg_lifetime( + x: usize, + y: ... +) -> &usize { //~ ERROR missing lifetime specifier + &0 +} + +pub unsafe extern "C" fn use_normal_arg_lifetime(x: &usize, y: ...) -> &usize { // OK + x +} diff --git a/src/test/ui/c-variadic/variadic-ffi-6.stderr b/src/test/ui/c-variadic/variadic-ffi-6.stderr new file mode 100644 index 00000000000..76bd18959a5 --- /dev/null +++ b/src/test/ui/c-variadic/variadic-ffi-6.stderr @@ -0,0 +1,11 @@ +error[E0106]: missing lifetime specifier + --> $DIR/variadic-ffi-6.rs:7:6 + | +LL | ) -> &usize { //~ ERROR missing lifetime specifier + | ^ help: consider giving it an explicit bounded or 'static lifetime: `&'static` + | + = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/error-codes/E0617.rs b/src/test/ui/error-codes/E0617.rs index 9eed1225ab8..51f13c7dbd5 100644 --- a/src/test/ui/error-codes/E0617.rs +++ b/src/test/ui/error-codes/E0617.rs @@ -22,7 +22,7 @@ fn main() { //~^ ERROR can't pass `u16` to variadic function //~| HELP cast the value to `c_uint` printf(::std::ptr::null(), printf); - //~^ ERROR can't pass `unsafe extern "C" fn(*const i8, ...) {printf}` to variadic function - //~| HELP cast the value to `unsafe extern "C" fn(*const i8, ...)` + //~^ ERROR can't pass `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaList<'r>, ...) {printf}` to variadic function + //~| HELP cast the value to `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaList<'r>, ...)` } } diff --git a/src/test/ui/error-codes/E0617.stderr b/src/test/ui/error-codes/E0617.stderr index 486ca1fa92f..8387d5c7e93 100644 --- a/src/test/ui/error-codes/E0617.stderr +++ b/src/test/ui/error-codes/E0617.stderr @@ -28,15 +28,15 @@ error[E0617]: can't pass `u16` to variadic function LL | printf(::std::ptr::null(), 0u16); | ^^^^ help: cast the value to `c_uint`: `0u16 as c_uint` -error[E0617]: can't pass `unsafe extern "C" fn(*const i8, ...) {printf}` to variadic function +error[E0617]: can't pass `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaList<'r>, ...) {printf}` to variadic function --> $DIR/E0617.rs:24:36 | LL | printf(::std::ptr::null(), printf); | ^^^^^^ -help: cast the value to `unsafe extern "C" fn(*const i8, ...)` +help: cast the value to `for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaList<'r>, ...)` | -LL | printf(::std::ptr::null(), printf as unsafe extern "C" fn(*const i8, ...)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | printf(::std::ptr::null(), printf as for<'r> unsafe extern "C" fn(*const i8, std::ffi::VaList<'r>, ...)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/recover-enum2.stderr b/src/test/ui/parser/recover-enum2.stderr index 2473420a779..b308e644ad9 100644 --- a/src/test/ui/parser/recover-enum2.stderr +++ b/src/test/ui/parser/recover-enum2.stderr @@ -10,11 +10,11 @@ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `{` LL | Nope(i32 {}) //~ ERROR: found `{` | ^ expected one of 7 possible tokens here -error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `::`, `<`, `?`, `[`, `_`, `crate`, `dyn`, `extern`, `fn`, `for`, `impl`, `pub`, `unsafe`, `}`, or lifetime, found `{` +error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `...`, `::`, `<`, `?`, `[`, `_`, `crate`, `dyn`, `extern`, `fn`, `for`, `impl`, `pub`, `unsafe`, `}`, or lifetime, found `{` --> $DIR/recover-enum2.rs:27:22 | LL | Nope(i32 {}) //~ ERROR: found `{` - | ^ expected one of 23 possible tokens here + | ^ expected one of 24 possible tokens here error: expected expression, found reserved identifier `_` --> $DIR/recover-enum2.rs:32:22 diff --git a/src/test/ui/variadic/variadic-ffi-2.rs b/src/test/ui/variadic/variadic-ffi-2.rs deleted file mode 100644 index 224ac16f458..00000000000 --- a/src/test/ui/variadic/variadic-ffi-2.rs +++ /dev/null @@ -1,8 +0,0 @@ -// ignore-arm stdcall isn't supported - -fn baz(f: extern "stdcall" fn(usize, ...)) { - //~^ ERROR: variadic function must have C or cdecl calling convention - f(22, 44); -} - -fn main() {} diff --git a/src/test/ui/variadic/variadic-ffi-2.stderr b/src/test/ui/variadic/variadic-ffi-2.stderr deleted file mode 100644 index cb2a9f874b7..00000000000 --- a/src/test/ui/variadic/variadic-ffi-2.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0045]: variadic function must have C or cdecl calling convention - --> $DIR/variadic-ffi-2.rs:3:11 - | -LL | fn baz(f: extern "stdcall" fn(usize, ...)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variadics require C or cdecl calling convention - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0045`. diff --git a/src/test/ui/variadic/variadic-ffi-3.rs b/src/test/ui/variadic/variadic-ffi-3.rs deleted file mode 100644 index 12b3426d9da..00000000000 --- a/src/test/ui/variadic/variadic-ffi-3.rs +++ /dev/null @@ -1,31 +0,0 @@ -extern { - fn foo(f: isize, x: u8, ...); - //~^ defined here - //~| defined here -} - -extern "C" fn bar(f: isize, x: u8) {} - -fn main() { - unsafe { - foo(); //~ ERROR: this function takes at least 2 parameters but 0 parameters were supplied - foo(1); //~ ERROR: this function takes at least 2 parameters but 1 parameter was supplied - - let x: unsafe extern "C" fn(f: isize, x: u8) = foo; - //~^ ERROR: mismatched types - //~| expected type `unsafe extern "C" fn(isize, u8)` - //~| found type `unsafe extern "C" fn(isize, u8, ...) {foo}` - - let y: extern "C" fn(f: isize, x: u8, ...) = bar; - //~^ ERROR: mismatched types - //~| expected type `extern "C" fn(isize, u8, ...)` - //~| found type `extern "C" fn(isize, u8) {bar}` - - foo(1, 2, 3f32); //~ ERROR can't pass `f32` to variadic function - foo(1, 2, true); //~ ERROR can't pass `bool` to variadic function - foo(1, 2, 1i8); //~ ERROR can't pass `i8` to variadic function - foo(1, 2, 1u8); //~ ERROR can't pass `u8` to variadic function - foo(1, 2, 1i16); //~ ERROR can't pass `i16` to variadic function - foo(1, 2, 1u16); //~ ERROR can't pass `u16` to variadic function - } -} diff --git a/src/test/ui/variadic/variadic-ffi-3.stderr b/src/test/ui/variadic/variadic-ffi-3.stderr deleted file mode 100644 index 0fecbbf36b8..00000000000 --- a/src/test/ui/variadic/variadic-ffi-3.stderr +++ /dev/null @@ -1,76 +0,0 @@ -error[E0060]: this function takes at least 2 parameters but 0 parameters were supplied - --> $DIR/variadic-ffi-3.rs:11:9 - | -LL | fn foo(f: isize, x: u8, ...); - | ----------------------------- defined here -... -LL | foo(); //~ ERROR: this function takes at least 2 parameters but 0 parameters were supplied - | ^^^^^ expected at least 2 parameters - -error[E0060]: this function takes at least 2 parameters but 1 parameter was supplied - --> $DIR/variadic-ffi-3.rs:12:9 - | -LL | fn foo(f: isize, x: u8, ...); - | ----------------------------- defined here -... -LL | foo(1); //~ ERROR: this function takes at least 2 parameters but 1 parameter was supplied - | ^^^^^^ expected at least 2 parameters - -error[E0308]: mismatched types - --> $DIR/variadic-ffi-3.rs:14:56 - | -LL | let x: unsafe extern "C" fn(f: isize, x: u8) = foo; - | ^^^ expected non-variadic fn, found variadic function - | - = note: expected type `unsafe extern "C" fn(isize, u8)` - found type `unsafe extern "C" fn(isize, u8, ...) {foo}` - -error[E0308]: mismatched types - --> $DIR/variadic-ffi-3.rs:19:54 - | -LL | let y: extern "C" fn(f: isize, x: u8, ...) = bar; - | ^^^ expected variadic fn, found non-variadic function - | - = note: expected type `extern "C" fn(isize, u8, ...)` - found type `extern "C" fn(isize, u8) {bar}` - -error[E0617]: can't pass `f32` to variadic function - --> $DIR/variadic-ffi-3.rs:24:19 - | -LL | foo(1, 2, 3f32); //~ ERROR can't pass `f32` to variadic function - | ^^^^ help: cast the value to `c_double`: `3f32 as c_double` - -error[E0617]: can't pass `bool` to variadic function - --> $DIR/variadic-ffi-3.rs:25:19 - | -LL | foo(1, 2, true); //~ ERROR can't pass `bool` to variadic function - | ^^^^ help: cast the value to `c_int`: `true as c_int` - -error[E0617]: can't pass `i8` to variadic function - --> $DIR/variadic-ffi-3.rs:26:19 - | -LL | foo(1, 2, 1i8); //~ ERROR can't pass `i8` to variadic function - | ^^^ help: cast the value to `c_int`: `1i8 as c_int` - -error[E0617]: can't pass `u8` to variadic function - --> $DIR/variadic-ffi-3.rs:27:19 - | -LL | foo(1, 2, 1u8); //~ ERROR can't pass `u8` to variadic function - | ^^^ help: cast the value to `c_uint`: `1u8 as c_uint` - -error[E0617]: can't pass `i16` to variadic function - --> $DIR/variadic-ffi-3.rs:28:19 - | -LL | foo(1, 2, 1i16); //~ ERROR can't pass `i16` to variadic function - | ^^^^ help: cast the value to `c_int`: `1i16 as c_int` - -error[E0617]: can't pass `u16` to variadic function - --> $DIR/variadic-ffi-3.rs:29:19 - | -LL | foo(1, 2, 1u16); //~ ERROR can't pass `u16` to variadic function - | ^^^^ help: cast the value to `c_uint`: `1u16 as c_uint` - -error: aborting due to 10 previous errors - -Some errors occurred: E0060, E0308, E0617. -For more information about an error, try `rustc --explain E0060`. diff --git a/src/test/ui/variadic/variadic-ffi.rs b/src/test/ui/variadic/variadic-ffi.rs deleted file mode 100644 index 61b2ad4bed5..00000000000 --- a/src/test/ui/variadic/variadic-ffi.rs +++ /dev/null @@ -1,31 +0,0 @@ -// ignore-arm stdcall isn't supported -// ignore-aarch64 stdcall isn't supported - -extern "stdcall" { - fn printf(_: *const u8, ...); //~ ERROR: variadic function must have C or cdecl calling -} - -extern { - fn foo(f: isize, x: u8, ...); -} - -extern "C" fn bar(f: isize, x: u8) {} - -fn main() { - // errors below are no longer checked because error above aborts - // compilation; see variadic-ffi-3.rs for corresponding test. - unsafe { - foo(); - foo(1); - - let x: unsafe extern "C" fn(f: isize, x: u8) = foo; - let y: extern "C" fn(f: isize, x: u8, ...) = bar; - - foo(1, 2, 3f32); - foo(1, 2, true); - foo(1, 2, 1i8); - foo(1, 2, 1u8); - foo(1, 2, 1i16); - foo(1, 2, 1u16); - } -} diff --git a/src/test/ui/variadic/variadic-ffi.stderr b/src/test/ui/variadic/variadic-ffi.stderr deleted file mode 100644 index 617b1f46ea3..00000000000 --- a/src/test/ui/variadic/variadic-ffi.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0045]: variadic function must have C or cdecl calling convention - --> $DIR/variadic-ffi.rs:5:5 - | -LL | fn printf(_: *const u8, ...); //~ ERROR: variadic function must have C or cdecl calling - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variadics require C or cdecl calling convention - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0045`. -- cgit 1.4.1-3-g733a5 From 08bd4ff9987fc57215a2fe54c63da0e86d9e6fbf Mon Sep 17 00:00:00 2001 From: Dan Robertson Date: Fri, 8 Feb 2019 17:30:42 +0000 Subject: Rename variadic to c_variadic Function signatures with the `variadic` member set are actually C-variadic functions. Make this a little more explicit by renaming the `variadic` boolean value, `c_variadic`. --- src/librustc/hir/lowering.rs | 6 +-- src/librustc/hir/mod.rs | 2 +- src/librustc/hir/print.rs | 2 +- src/librustc/ich/impls_hir.rs | 2 +- src/librustc/ich/impls_ty.rs | 2 +- src/librustc/traits/select.rs | 2 +- src/librustc/ty/context.rs | 6 +-- src/librustc/ty/instance.rs | 2 +- src/librustc/ty/relate.rs | 6 +-- src/librustc/ty/structural_impls.rs | 4 +- src/librustc/ty/sty.rs | 8 ++-- src/librustc/util/ppaux.rs | 8 ++-- src/librustc_codegen_llvm/abi.rs | 10 ++--- src/librustc_codegen_llvm/debuginfo/type_names.rs | 2 +- src/librustc_codegen_ssa/mir/block.rs | 6 +-- src/librustc_codegen_ssa/mir/mod.rs | 2 +- src/librustc_lint/types.rs | 2 +- .../borrow_check/nll/type_check/mod.rs | 4 +- src/librustc_mir/monomorphize/item.rs | 2 +- src/librustc_target/abi/call/arm.rs | 2 +- src/librustc_target/abi/call/mod.rs | 2 +- .../chalk_context/program_clauses.rs | 8 ++-- src/librustc_traits/generic_types.rs | 4 +- src/librustc_typeck/astconv.rs | 6 +-- src/librustc_typeck/check/callee.rs | 6 +-- src/librustc_typeck/check/closure.rs | 10 ++--- src/librustc_typeck/check/mod.rs | 24 +++++------ src/librustc_typeck/lib.rs | 14 +++---- src/libsyntax/ast.rs | 2 +- src/libsyntax/ext/build.rs | 2 +- src/libsyntax/mut_visit.rs | 2 +- src/libsyntax/parse/parser.rs | 48 +++++++++++----------- src/libsyntax/print/pprust.rs | 4 +- .../run-pass-fulldeps/pprust-expr-roundtrip.rs | 2 +- src/test/ui/c-variadic/variadic-ffi-1.stderr | 4 +- src/test/ui/c-variadic/variadic-ffi-2.stderr | 4 +- src/test/ui/error-codes/E0045.stderr | 4 +- src/test/ui/invalid/invalid-variadic-function.rs | 2 +- .../ui/invalid/invalid-variadic-function.stderr | 2 +- src/test/ui/parser/variadic-ffi-3.rs | 2 +- src/test/ui/parser/variadic-ffi-3.stderr | 2 +- src/test/ui/parser/variadic-ffi-4.rs | 2 +- src/test/ui/parser/variadic-ffi-4.stderr | 2 +- 43 files changed, 119 insertions(+), 119 deletions(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 0e2b34d4fac..6e96054bea9 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -954,7 +954,7 @@ impl<'a> LoweringContext<'a> { let decl = FnDecl { inputs: vec![], output, - variadic: false + c_variadic: false }; let body_id = self.record_body(body_expr, Some(&decl)); self.is_generator = prev_is_generator; @@ -2118,7 +2118,7 @@ impl<'a> LoweringContext<'a> { P(hir::FnDecl { inputs, output, - variadic: decl.variadic, + c_variadic: decl.c_variadic, implicit_self: decl.inputs.get(0).map_or( hir::ImplicitSelfKind::None, |arg| { @@ -3973,7 +3973,7 @@ impl<'a> LoweringContext<'a> { let outer_decl = FnDecl { inputs: decl.inputs.clone(), output: FunctionRetTy::Default(fn_decl_span), - variadic: false, + c_variadic: false, }; // We need to lower the declaration outside the new scope, because we // have to conserve the state of being inside a loop condition for the diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 205109d18fe..d8169d05dd4 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1868,7 +1868,7 @@ pub struct Arg { pub struct FnDecl { pub inputs: HirVec, pub output: FunctionRetTy, - pub variadic: bool, + pub c_variadic: bool, /// Does the function have an implicit self? pub implicit_self: ImplicitSelfKind, } diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 8c252b0d027..dab4b9c824d 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -2007,7 +2007,7 @@ impl<'a> State<'a> { s.print_type(ty)?; s.end() })?; - if decl.variadic { + if decl.c_variadic { self.s.word(", ...")?; } self.pclose()?; diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index b7ec5889d6a..77582278690 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -368,7 +368,7 @@ impl_stable_hash_for!(enum hir::TyKind { impl_stable_hash_for!(struct hir::FnDecl { inputs, output, - variadic, + c_variadic, implicit_self }); diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index cce1273b7f0..f77a88128f2 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -232,7 +232,7 @@ impl_stable_hash_for!(struct ty::GenSig<'tcx> { impl_stable_hash_for!(struct ty::FnSig<'tcx> { inputs_and_output, - variadic, + c_variadic, unsafety, abi }); diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index e85b84bce43..e7cc9618080 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1944,7 +1944,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { if let ty::FnSig { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, - variadic: false, + c_variadic: false, .. } = self_ty.fn_sig(self.tcx()).skip_binder() { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index b37b632f4be..9767396147c 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -2453,7 +2453,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_fn_sig( params_iter, s.output(), - s.variadic, + s.c_variadic, hir::Unsafety::Normal, abi::Abi::Rust, ) @@ -2779,7 +2779,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_fn_sig(self, inputs: I, output: I::Item, - variadic: bool, + c_variadic: bool, unsafety: hir::Unsafety, abi: abi::Abi) -> , ty::FnSig<'tcx>>>::Output @@ -2788,7 +2788,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { inputs.chain(iter::once(output)).intern_with(|xs| ty::FnSig { inputs_and_output: self.intern_type_list(xs), - variadic, unsafety, abi + c_variadic, unsafety, abi }) } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 709dce4589f..49ebd202813 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -65,7 +65,7 @@ impl<'a, 'tcx> Instance<'tcx> { sig.map_bound(|sig| tcx.mk_fn_sig( iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), sig.output(), - sig.variadic, + sig.c_variadic, sig.unsafety, sig.abi )) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index b15aa862901..2940757fa90 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -147,9 +147,9 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { { let tcx = relation.tcx(); - if a.variadic != b.variadic { + if a.c_variadic != b.c_variadic { return Err(TypeError::VariadicMismatch( - expected_found(relation, &a.variadic, &b.variadic))); + expected_found(relation, &a.c_variadic, &b.c_variadic))); } let unsafety = relation.relate(&a.unsafety, &b.unsafety)?; let abi = relation.relate(&a.abi, &b.abi)?; @@ -171,7 +171,7 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { }); Ok(ty::FnSig { inputs_and_output: tcx.mk_type_list(inputs_and_output)?, - variadic: a.variadic, + c_variadic: a.c_variadic, unsafety, abi, }) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index a81d5c9d86e..f1a465e1f17 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -396,7 +396,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::FnSig<'a> { tcx.lift(&self.inputs_and_output).map(|x| { ty::FnSig { inputs_and_output: x, - variadic: self.variadic, + c_variadic: self.c_variadic, unsafety: self.unsafety, abi: self.abi, } @@ -832,7 +832,7 @@ BraceStructTypeFoldableImpl! { BraceStructTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> { - inputs_and_output, variadic, unsafety, abi + inputs_and_output, c_variadic, unsafety, abi } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 7ade035ce89..3fd2e38a3d3 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -979,11 +979,11 @@ impl<'tcx> PolyGenSig<'tcx> { /// /// - `inputs`: is the list of arguments and their modes. /// - `output`: is the return type. -/// - `variadic`: indicates whether this is a C-variadic function. +/// - `c_variadic`: indicates whether this is a C-variadic function. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct FnSig<'tcx> { pub inputs_and_output: &'tcx List>, - pub variadic: bool, + pub c_variadic: bool, pub unsafety: hir::Unsafety, pub abi: abi::Abi, } @@ -1016,8 +1016,8 @@ impl<'tcx> PolyFnSig<'tcx> { pub fn output(&self) -> ty::Binder> { self.map_bound_ref(|fn_sig| fn_sig.output()) } - pub fn variadic(&self) -> bool { - self.skip_binder().variadic + pub fn c_variadic(&self) -> bool { + self.skip_binder().c_variadic } pub fn unsafety(&self) -> hir::Unsafety { self.skip_binder().unsafety diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index fbe9e3359bf..aecef3c5ec7 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -360,7 +360,7 @@ impl PrintContext { fn fn_sig(&mut self, f: &mut F, inputs: &[Ty<'_>], - variadic: bool, + c_variadic: bool, output: Ty<'_>) -> fmt::Result { write!(f, "(")?; @@ -370,7 +370,7 @@ impl PrintContext { for &ty in inputs { print!(f, self, write(", "), print_display(ty))?; } - if variadic { + if c_variadic { write!(f, ", ...")?; } } @@ -1074,10 +1074,10 @@ define_print! { } write!(f, "fn")?; - cx.fn_sig(f, self.inputs(), self.variadic, self.output()) + cx.fn_sig(f, self.inputs(), self.c_variadic, self.output()) } debug { - write!(f, "({:?}; variadic: {})->{:?}", self.inputs(), self.variadic, self.output()) + write!(f, "({:?}; c_variadic: {})->{:?}", self.inputs(), self.c_variadic, self.output()) } } } diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index aea62360651..49c9555a2c6 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -422,7 +422,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { let mut inputs = sig.inputs(); let extra_args = if sig.abi == RustCall { - assert!(!sig.variadic && extra_args.is_empty()); + assert!(!sig.c_variadic && extra_args.is_empty()); match sig.inputs().last().unwrap().sty { ty::Tuple(ref tupled_arguments) => { @@ -435,7 +435,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { } } } else { - assert!(sig.variadic || extra_args.is_empty()); + assert!(sig.c_variadic || extra_args.is_empty()); extra_args }; @@ -531,7 +531,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { // If this is a C-variadic function, this is not the return value, // and there is one or more fixed arguments; ensure that the `VaList` // is ignored as an argument. - if sig.variadic { + if sig.c_variadic { match (last_arg_idx, arg_idx) { (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => { let va_list_did = match cx.tcx.lang_items().va_list() { @@ -589,7 +589,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { args: inputs.iter().chain(extra_args).enumerate().map(|(i, ty)| { arg_of(ty, Some(i)) }).collect(), - variadic: sig.variadic, + c_variadic: sig.c_variadic, conv, }; fn_ty.adjust_for_abi(cx, sig.abi); @@ -717,7 +717,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { llargument_tys.push(llarg_ty); } - if self.variadic { + if self.c_variadic { cx.type_variadic_func(&llargument_tys, llreturn_ty) } else { cx.type_func(&llargument_tys, llreturn_ty) diff --git a/src/librustc_codegen_llvm/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs index 176c9b8c542..8b218ab39d9 100644 --- a/src/librustc_codegen_llvm/debuginfo/type_names.rs +++ b/src/librustc_codegen_llvm/debuginfo/type_names.rs @@ -143,7 +143,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, output.pop(); } - if sig.variadic { + if sig.c_variadic { if !sig.inputs().is_empty() { output.push_str(", ..."); } else { diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 684dfac991b..627380ee38f 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -232,7 +232,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &mut self, mut bx: Bx, ) { - if self.fn_ty.variadic { + if self.fn_ty.c_variadic { if let Some(va_list) = self.va_list_ref { bx.va_end(va_list.llval); } @@ -507,7 +507,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // The "spoofed" `VaList` added to a C-variadic functions signature // should not be included in the `extra_args` calculation. - let extra_args_start_idx = sig.inputs().len() - if sig.variadic { 1 } else { 0 }; + let extra_args_start_idx = sig.inputs().len() - if sig.c_variadic { 1 } else { 0 }; let extra_args = &args[extra_args_start_idx..]; let extra_args = extra_args.iter().map(|op_arg| { let op_ty = op_arg.ty(self.mir, bx.tcx()); @@ -695,7 +695,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // an "spoofed" `VaList`. This argument is ignored, but we need to // populate it with a dummy operand so that the users real arguments // are not overwritten. - let i = if sig.variadic && last_arg_idx.map(|x| x == i).unwrap_or(false) { + let i = if sig.c_variadic && last_arg_idx.map(|x| x == i).unwrap_or(false) { let layout = match self.cx.tcx().lang_items().va_list() { Some(did) => bx.cx().layout_of(bx.tcx().type_of(did)), None => bug!("`va_list` language item required for C-variadics"), diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 95cf8cfe2d0..dc77d4673cd 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -585,7 +585,7 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( indirect_operand.store(bx, tmp); tmp } else { - if fx.fn_ty.variadic && last_arg_idx.map(|idx| arg_index == idx).unwrap_or(false) { + if fx.fn_ty.c_variadic && last_arg_idx.map(|idx| arg_index == idx).unwrap_or(false) { let va_list_impl = match arg_decl.ty.ty_adt_def() { Some(adt) => adt.non_enum_variant(), None => bug!("`va_list` language item improperly constructed") diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index fb279a5d9b8..35489ab42e7 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -766,7 +766,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let def_id = self.cx.tcx.hir().local_def_id(id); let sig = self.cx.tcx.fn_sig(def_id); let sig = self.cx.tcx.erase_late_bound_regions(&sig); - let inputs = if sig.variadic { + let inputs = if sig.c_variadic { // Don't include the spoofed `VaList` in the functions list // of inputs. &sig.inputs()[..sig.inputs().len() - 1] diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index f897795d86f..df035aab54c 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1604,12 +1604,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { debug!("check_call_inputs({:?}, {:?})", sig, args); // Do not count the `VaList` argument as a "true" argument to // a C-variadic function. - let inputs = if sig.variadic { + let inputs = if sig.c_variadic { &sig.inputs()[..sig.inputs().len() - 1] } else { &sig.inputs()[..] }; - if args.len() < inputs.len() || (args.len() > inputs.len() && !sig.variadic) { + if args.len() < inputs.len() || (args.len() > inputs.len() && !sig.c_variadic) { span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); } for (n, (fn_arg, op_arg)) in inputs.iter().zip(args).enumerate() { diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index a26a1a7861e..059af2dbba9 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -353,7 +353,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { output.pop(); } - if sig.variadic { + if sig.c_variadic { if !sig.inputs().is_empty() { output.push_str(", ..."); } else { diff --git a/src/librustc_target/abi/call/arm.rs b/src/librustc_target/abi/call/arm.rs index 52d7f3ac3dc..e3fee8e5700 100644 --- a/src/librustc_target/abi/call/arm.rs +++ b/src/librustc_target/abi/call/arm.rs @@ -99,7 +99,7 @@ pub fn compute_abi_info<'a, Ty, C>(cx: &C, fty: &mut FnType<'a, Ty>) // `extern "aapcs"`, then we must use the VFP registers for homogeneous aggregates. let vfp = cx.target_spec().llvm_target.ends_with("hf") && fty.conv != Conv::ArmAapcs - && !fty.variadic; + && !fty.c_variadic; if !fty.ret.is_ignore() { classify_ret_ty(cx, &mut fty.ret, vfp); diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index 8ada328a158..fbbd120f934 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -531,7 +531,7 @@ pub struct FnType<'a, Ty> { /// LLVM return type. pub ret: ArgType<'a, Ty>, - pub variadic: bool, + pub c_variadic: bool, pub conv: Conv, } diff --git a/src/librustc_traits/chalk_context/program_clauses.rs b/src/librustc_traits/chalk_context/program_clauses.rs index 4d8a67ca638..3f88d0e08b4 100644 --- a/src/librustc_traits/chalk_context/program_clauses.rs +++ b/src/librustc_traits/chalk_context/program_clauses.rs @@ -105,7 +105,7 @@ fn assemble_builtin_sized_impls<'tcx>( let fn_ptr = generic_types::fn_ptr( tcx, fn_ptr.inputs_and_output.len(), - fn_ptr.variadic, + fn_ptr.c_variadic, fn_ptr.unsafety, fn_ptr.abi ); @@ -190,11 +190,11 @@ fn wf_clause_for_raw_ptr<'tcx>( fn wf_clause_for_fn_ptr<'tcx>( tcx: ty::TyCtxt<'_, '_, 'tcx>, arity_and_output: usize, - variadic: bool, + c_variadic: bool, unsafety: hir::Unsafety, abi: abi::Abi ) -> Clauses<'tcx> { - let fn_ptr = generic_types::fn_ptr(tcx, arity_and_output, variadic, unsafety, abi); + let fn_ptr = generic_types::fn_ptr(tcx, arity_and_output, c_variadic, unsafety, abi); let wf_clause = ProgramClause { goal: DomainGoal::WellFormed(WellFormed::Ty(fn_ptr)), @@ -503,7 +503,7 @@ impl ChalkInferenceContext<'cx, 'gcx, 'tcx> { wf_clause_for_fn_ptr( self.infcx.tcx, fn_ptr.inputs_and_output.len(), - fn_ptr.variadic, + fn_ptr.c_variadic, fn_ptr.unsafety, fn_ptr.abi ) diff --git a/src/librustc_traits/generic_types.rs b/src/librustc_traits/generic_types.rs index 634c024b064..f2ce9631f35 100644 --- a/src/librustc_traits/generic_types.rs +++ b/src/librustc_traits/generic_types.rs @@ -24,7 +24,7 @@ crate fn raw_ptr(tcx: TyCtxt<'_, '_, 'tcx>, mutbl: hir::Mutability) -> Ty<'tcx> crate fn fn_ptr( tcx: ty::TyCtxt<'_, '_, 'tcx>, arity_and_output: usize, - variadic: bool, + c_variadic: bool, unsafety: hir::Unsafety, abi: abi::Abi ) -> Ty<'tcx> { @@ -37,7 +37,7 @@ crate fn fn_ptr( let fn_sig = ty::Binder::bind(ty::FnSig { inputs_and_output, - variadic, + c_variadic, unsafety, abi, }); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1d99584eec4..b3694752204 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -18,7 +18,7 @@ use rustc::ty::subst::{Kind, Subst, InternalSubsts, SubstsRef}; use rustc::ty::wf::object_region_bounds; use rustc_data_structures::sync::Lrc; use rustc_target::spec::abi; -use crate::require_c_abi_if_variadic; +use crate::require_c_abi_if_c_variadic; use smallvec::SmallVec; use syntax::ast; use syntax::feature_gate::{GateIssue, emit_feature_err}; @@ -1768,7 +1768,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { tcx.mk_tup(fields.iter().map(|t| self.ast_ty_to_ty(&t))) } hir::TyKind::BareFn(ref bf) => { - require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); + require_c_abi_if_c_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); tcx.mk_fn_ptr(self.ty_of_fn(bf.unsafety, bf.abi, &bf.decl)) } hir::TyKind::TraitObject(ref bounds, ref lifetime) => { @@ -1913,7 +1913,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let bare_fn_ty = ty::Binder::bind(tcx.mk_fn_sig( input_tys, output_ty, - decl.variadic, + decl.c_variadic, unsafety, abi )); diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index aeb43635eb7..0a4c0eb3aff 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -368,7 +368,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .0; let fn_sig = self.normalize_associated_types_in(call_expr.span, &fn_sig); - let inputs = if fn_sig.variadic { + let inputs = if fn_sig.c_variadic { if fn_sig.inputs().len() > 1 { &fn_sig.inputs()[..fn_sig.inputs().len() - 1] } else { @@ -391,7 +391,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { inputs, &expected_arg_tys[..], arg_exprs, - fn_sig.variadic, + fn_sig.c_variadic, TupleArgumentsFlag::DontTupleArguments, def_span, ); @@ -424,7 +424,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn_sig.inputs(), &expected_arg_tys, arg_exprs, - fn_sig.variadic, + fn_sig.c_variadic, TupleArgumentsFlag::TupleArguments, None, ); diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 2a4b17a6399..db89b32be7b 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -141,7 +141,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tcx.mk_fn_sig( iter::once(self.tcx.intern_tup(sig.inputs())), sig.output(), - sig.variadic, + sig.c_variadic, sig.unsafety, sig.abi, ) @@ -386,7 +386,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Watch out for some surprises and just ignore the // expectation if things don't see to match up with what we // expect. - if expected_sig.sig.variadic != decl.variadic { + if expected_sig.sig.c_variadic != decl.c_variadic { return self.sig_of_closure_no_expectation(expr_def_id, decl, body); } else if expected_sig.sig.inputs_and_output.len() != decl.inputs.len() + 1 { return self.sig_of_closure_with_mismatched_number_of_arguments( @@ -404,7 +404,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let bound_sig = ty::Binder::bind(self.tcx.mk_fn_sig( expected_sig.sig.inputs().iter().cloned(), expected_sig.sig.output(), - decl.variadic, + decl.c_variadic, hir::Unsafety::Normal, Abi::RustCall, )); @@ -586,7 +586,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let result = ty::Binder::bind(self.tcx.mk_fn_sig( supplied_arguments, supplied_return, - decl.variadic, + decl.c_variadic, hir::Unsafety::Normal, Abi::RustCall, )); @@ -621,7 +621,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let result = ty::Binder::bind(self.tcx.mk_fn_sig( supplied_arguments, self.tcx.types.err, - decl.variadic, + decl.c_variadic, hir::Unsafety::Normal, Abi::RustCall, )); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 202d8bec4e9..3a430f77b6c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -130,7 +130,7 @@ use std::mem::replace; use std::ops::{self, Deref}; use std::slice; -use crate::require_c_abi_if_variadic; +use crate::require_c_abi_if_c_variadic; use crate::session::{CompileIncomplete, Session}; use crate::session::config::EntryFnType; use crate::TypeAndSubsts; @@ -1072,7 +1072,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fn_sig = fcx.tcx.mk_fn_sig( fn_sig.inputs().iter().cloned(), revealed_ret_ty, - fn_sig.variadic, + fn_sig.c_variadic, fn_sig.unsafety, fn_sig.abi ); @@ -1426,7 +1426,7 @@ pub fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Ite } if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.node { - require_c_abi_if_variadic(tcx, fn_decl, m.abi, item.span); + require_c_abi_if_c_variadic(tcx, fn_decl, m.abi, item.span); } } } @@ -2783,7 +2783,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &method.sig.inputs()[1..] ); self.check_argument_types(sp, expr_sp, &method.sig.inputs()[1..], &expected_arg_tys[..], - args_no_rcvr, method.sig.variadic, tuple_arguments, + args_no_rcvr, method.sig.c_variadic, tuple_arguments, self.tcx.hir().span_if_local(method.def_id)); method.sig.output() } @@ -2862,7 +2862,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn_inputs: &[Ty<'tcx>], mut expected_arg_tys: &[Ty<'tcx>], args: &'gcx [hir::Expr], - variadic: bool, + c_variadic: bool, tuple_arguments: TupleArgumentsFlag, def_span: Option) { let tcx = self.tcx; @@ -2886,11 +2886,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let param_count_error = |expected_count: usize, arg_count: usize, error_code: &str, - variadic: bool, + c_variadic: bool, sugg_unit: bool| { let mut err = tcx.sess.struct_span_err_with_code(sp, &format!("this function takes {}{} but {} {} supplied", - if variadic {"at least "} else {""}, + if c_variadic { "at least " } else { "" }, potentially_plural_count(expected_count, "parameter"), potentially_plural_count(arg_count, "parameter"), if arg_count == 1 {"was"} else {"were"}), @@ -2910,7 +2910,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Applicability::MachineApplicable); } else { err.span_label(sp, format!("expected {}{}", - if variadic {"at least "} else {""}, + if c_variadic { "at least " } else { "" }, potentially_plural_count(expected_count, "parameter"))); } err.emit(); @@ -2944,7 +2944,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } else if expected_arg_count == supplied_arg_count { fn_inputs.to_vec() - } else if variadic { + } else if c_variadic { if supplied_arg_count >= expected_arg_count { fn_inputs.to_vec() } else { @@ -2991,10 +2991,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.select_obligations_where_possible(false); } - // For variadic functions, we don't have a declared type for all of + // For C-variadic functions, we don't have a declared type for all of // the arguments hence we only do our usual type checking with // the arguments who's types we do know. - let t = if variadic { + let t = if c_variadic { expected_arg_count } else if tuple_arguments == TupleArguments { args.len() @@ -3043,7 +3043,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // We also need to make sure we at least write the ty of the other // arguments which we skipped above. - if variadic { + if c_variadic { fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) { use crate::structured_errors::{VariadicError, StructuredDiagnostic}; VariadicError::new(s, span, t, cast_ty).diagnostic().emit(); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 419796a2014..2095c81d0fb 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -136,14 +136,14 @@ fn check_type_alias_enum_variants_enabled<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, } } -fn require_c_abi_if_variadic(tcx: TyCtxt<'_, '_, '_>, - decl: &hir::FnDecl, - abi: Abi, - span: Span) { - if decl.variadic && !(abi == Abi::C || abi == Abi::Cdecl) { +fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_, '_, '_>, + decl: &hir::FnDecl, + abi: Abi, + span: Span) { + if decl.c_variadic && !(abi == Abi::C || abi == Abi::Cdecl) { let mut err = struct_span_err!(tcx.sess, span, E0045, - "variadic function must have C or cdecl calling convention"); - err.span_label(span, "variadics require C or cdecl calling convention").emit(); + "C-variadic function must have C or cdecl calling convention"); + err.span_label(span, "C-variadics require C or cdecl calling convention").emit(); } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 5bae00b9cb8..b4bf6665d4e 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1804,7 +1804,7 @@ impl Arg { pub struct FnDecl { pub inputs: Vec, pub output: FunctionRetTy, - pub variadic: bool, + pub c_variadic: bool, } impl FnDecl { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 27b0cfb1630..0bdc7fd60cb 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -985,7 +985,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { P(ast::FnDecl { inputs, output, - variadic: false + c_variadic: false }) } diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 8efc4689cac..032a0e993ae 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -673,7 +673,7 @@ pub fn noop_visit_asyncness(asyncness: &mut IsAsync, vis: &mut T) } pub fn noop_visit_fn_decl(decl: &mut P, vis: &mut T) { - let FnDecl { inputs, output, variadic: _ } = decl.deref_mut(); + let FnDecl { inputs, output, c_variadic: _ } = decl.deref_mut(); visit_vec(inputs, |input| vis.visit_arg(input)); match output { FunctionRetTy::Default(span) => vis.visit_span(span), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b58091b57da..5f3b08bf942 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1457,12 +1457,12 @@ impl<'a> Parser<'a> { }; self.expect_keyword(keywords::Fn)?; - let (inputs, variadic) = self.parse_fn_args(false, true)?; + let (inputs, c_variadic) = self.parse_fn_args(false, true)?; let ret_ty = self.parse_ret_ty(false)?; let decl = P(FnDecl { inputs, output: ret_ty, - variadic, + c_variadic, }); Ok(TyKind::BareFn(P(BareFnTy { abi, @@ -1635,7 +1635,7 @@ impl<'a> Parser<'a> { } fn parse_ty_common(&mut self, allow_plus: bool, allow_qpath_recovery: bool, - allow_variadic: bool) -> PResult<'a, P> { + allow_c_variadic: bool) -> PResult<'a, P> { maybe_whole!(self, NtTy, |x| x); let lo = self.span; @@ -1773,12 +1773,12 @@ impl<'a> Parser<'a> { } } } else if self.check(&token::DotDotDot) { - if allow_variadic { + if allow_c_variadic { self.eat(&token::DotDotDot); TyKind::CVarArgs } else { return Err(self.fatal( - "only foreign functions are allowed to be variadic" + "only foreign functions are allowed to be C-variadic" )); } } else { @@ -1969,7 +1969,7 @@ impl<'a> Parser<'a> { /// This version of parse arg doesn't necessarily require identifier names. fn parse_arg_general(&mut self, require_name: bool, is_trait_item: bool, - allow_variadic: bool) -> PResult<'a, Arg> { + allow_c_variadic: bool) -> PResult<'a, Arg> { maybe_whole!(self, NtArg, |x| x); if let Ok(Some(_)) = self.parse_self_arg() { @@ -2018,12 +2018,12 @@ impl<'a> Parser<'a> { } self.eat_incorrect_doc_comment("a method argument's type"); - (pat, self.parse_ty_common(true, true, allow_variadic)?) + (pat, self.parse_ty_common(true, true, allow_c_variadic)?) } else { debug!("parse_arg_general ident_to_pat"); let parser_snapshot_before_ty = self.clone(); self.eat_incorrect_doc_comment("a method argument's type"); - let mut ty = self.parse_ty_common(true, true, allow_variadic); + let mut ty = self.parse_ty_common(true, true, allow_c_variadic); if ty.is_ok() && self.token != token::Comma && self.token != token::CloseDelim(token::Paren) { // This wasn't actually a type, but a pattern looking like a type, @@ -2042,7 +2042,7 @@ impl<'a> Parser<'a> { (pat, ty) } Err(mut err) => { - // If this is a variadic argument and we hit an error, return the + // If this is a C-variadic argument and we hit an error, return the // error. if self.token == token::DotDotDot { return Err(err); @@ -6122,12 +6122,12 @@ impl<'a> Parser<'a> { Ok(where_clause) } - fn parse_fn_args(&mut self, named_args: bool, allow_variadic: bool) + fn parse_fn_args(&mut self, named_args: bool, allow_c_variadic: bool) -> PResult<'a, (Vec , bool)> { self.expect(&token::OpenDelim(token::Paren))?; let sp = self.span; - let mut variadic = false; + let mut c_variadic = false; let (args, recovered): (Vec>, bool) = self.parse_seq_to_before_end( &token::CloseDelim(token::Paren), @@ -6141,14 +6141,14 @@ impl<'a> Parser<'a> { named_args }; match p.parse_arg_general(enforce_named_args, false, - allow_variadic) { + allow_c_variadic) { Ok(arg) => { if let TyKind::CVarArgs = arg.ty.node { - variadic = true; + c_variadic = true; if p.token != token::CloseDelim(token::Paren) { let span = p.span; p.span_err(span, - "`...` must be last in argument list in variadic function"); + "`...` must be the last argument of a C-variadic function"); Ok(None) } else { Ok(Some(arg)) @@ -6176,24 +6176,24 @@ impl<'a> Parser<'a> { let args: Vec<_> = args.into_iter().filter_map(|x| x).collect(); - if variadic && args.is_empty() { + if c_variadic && args.is_empty() { self.span_err(sp, - "variadic function must be declared with at least one named argument"); + "C-variadic function must be declared with at least one named argument"); } - Ok((args, variadic)) + Ok((args, c_variadic)) } /// Parses the argument list and result type of a function declaration. - fn parse_fn_decl(&mut self, allow_variadic: bool) -> PResult<'a, P> { + fn parse_fn_decl(&mut self, allow_c_variadic: bool) -> PResult<'a, P> { - let (args, variadic) = self.parse_fn_args(true, allow_variadic)?; + let (args, c_variadic) = self.parse_fn_args(true, allow_c_variadic)?; let ret_ty = self.parse_ret_ty(true)?; Ok(P(FnDecl { inputs: args, output: ret_ty, - variadic, + c_variadic, })) } @@ -6340,7 +6340,7 @@ impl<'a> Parser<'a> { Ok(P(FnDecl { inputs: fn_inputs, output: self.parse_ret_ty(true)?, - variadic: false + c_variadic: false })) } @@ -6366,7 +6366,7 @@ impl<'a> Parser<'a> { Ok(P(FnDecl { inputs: inputs_captures, output, - variadic: false + c_variadic: false })) } @@ -6398,8 +6398,8 @@ impl<'a> Parser<'a> { abi: Abi) -> PResult<'a, ItemInfo> { let (ident, mut generics) = self.parse_fn_header()?; - let allow_variadic = abi == Abi::C && unsafety == Unsafety::Unsafe; - let decl = self.parse_fn_decl(allow_variadic)?; + let allow_c_variadic = abi == Abi::C && unsafety == Unsafety::Unsafe; + let decl = self.parse_fn_decl(allow_c_variadic)?; generics.where_clause = self.parse_where_clause()?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; let header = FnHeader { unsafety, asyncness, constness, abi }; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index b3964d0ce9c..4f4336c5b27 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2814,7 +2814,7 @@ impl<'a> State<'a> { -> io::Result<()> { self.popen()?; self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, false))?; - if decl.variadic { + if decl.c_variadic { self.s.word(", ...")?; } self.pclose()?; @@ -3241,7 +3241,7 @@ mod tests { let decl = ast::FnDecl { inputs: Vec::new(), output: ast::FunctionRetTy::Default(syntax_pos::DUMMY_SP), - variadic: false + c_variadic: false }; let generics = ast::Generics::default(); assert_eq!( diff --git a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs index 956bc5ad862..80e0b0102af 100644 --- a/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/run-pass-fulldeps/pprust-expr-roundtrip.rs @@ -112,7 +112,7 @@ fn iter_exprs(depth: usize, f: &mut FnMut(P)) { let decl = P(FnDecl { inputs: vec![], output: FunctionRetTy::Default(DUMMY_SP), - variadic: false, + c_variadic: false, }); iter_exprs(depth - 1, &mut |e| g( ExprKind::Closure(CaptureBy::Value, diff --git a/src/test/ui/c-variadic/variadic-ffi-1.stderr b/src/test/ui/c-variadic/variadic-ffi-1.stderr index 52d7394d6af..61d55ce0d3e 100644 --- a/src/test/ui/c-variadic/variadic-ffi-1.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-1.stderr @@ -1,8 +1,8 @@ -error[E0045]: variadic function must have C or cdecl calling convention +error[E0045]: C-variadic function must have C or cdecl calling convention --> $DIR/variadic-ffi-1.rs:5:5 | LL | fn printf(_: *const u8, ...); //~ ERROR: variadic function must have C or cdecl calling - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variadics require C or cdecl calling convention + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadics require C or cdecl calling convention error: aborting due to previous error diff --git a/src/test/ui/c-variadic/variadic-ffi-2.stderr b/src/test/ui/c-variadic/variadic-ffi-2.stderr index cb2a9f874b7..4c8b8d2b2e1 100644 --- a/src/test/ui/c-variadic/variadic-ffi-2.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-2.stderr @@ -1,8 +1,8 @@ -error[E0045]: variadic function must have C or cdecl calling convention +error[E0045]: C-variadic function must have C or cdecl calling convention --> $DIR/variadic-ffi-2.rs:3:11 | LL | fn baz(f: extern "stdcall" fn(usize, ...)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ variadics require C or cdecl calling convention + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadics require C or cdecl calling convention error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0045.stderr b/src/test/ui/error-codes/E0045.stderr index b38bbc169bd..0ce91f0a401 100644 --- a/src/test/ui/error-codes/E0045.stderr +++ b/src/test/ui/error-codes/E0045.stderr @@ -1,8 +1,8 @@ -error[E0045]: variadic function must have C or cdecl calling convention +error[E0045]: C-variadic function must have C or cdecl calling convention --> $DIR/E0045.rs:1:17 | LL | extern "Rust" { fn foo(x: u8, ...); } //~ ERROR E0045 - | ^^^^^^^^^^^^^^^^^^^ variadics require C or cdecl calling convention + | ^^^^^^^^^^^^^^^^^^^ C-variadics require C or cdecl calling convention error: aborting due to previous error diff --git a/src/test/ui/invalid/invalid-variadic-function.rs b/src/test/ui/invalid/invalid-variadic-function.rs index aea630e7c26..8d23f0e4770 100644 --- a/src/test/ui/invalid/invalid-variadic-function.rs +++ b/src/test/ui/invalid/invalid-variadic-function.rs @@ -1,3 +1,3 @@ extern "C" fn foo(x: u8, ...); -//~^ ERROR only foreign functions are allowed to be variadic +//~^ ERROR only foreign functions are allowed to be C-variadic //~| ERROR expected one of `->`, `where`, or `{`, found `;` diff --git a/src/test/ui/invalid/invalid-variadic-function.stderr b/src/test/ui/invalid/invalid-variadic-function.stderr index 7a0b8066fd5..b2dbf8b9190 100644 --- a/src/test/ui/invalid/invalid-variadic-function.stderr +++ b/src/test/ui/invalid/invalid-variadic-function.stderr @@ -1,4 +1,4 @@ -error: only foreign functions are allowed to be variadic +error: only foreign functions are allowed to be C-variadic --> $DIR/invalid-variadic-function.rs:1:26 | LL | extern "C" fn foo(x: u8, ...); diff --git a/src/test/ui/parser/variadic-ffi-3.rs b/src/test/ui/parser/variadic-ffi-3.rs index 13bce27bb83..ce83cc87abe 100644 --- a/src/test/ui/parser/variadic-ffi-3.rs +++ b/src/test/ui/parser/variadic-ffi-3.rs @@ -1,5 +1,5 @@ fn foo(x: isize, ...) { - //~^ ERROR: only foreign functions are allowed to be variadic + //~^ ERROR: only foreign functions are allowed to be C-variadic } fn main() {} diff --git a/src/test/ui/parser/variadic-ffi-3.stderr b/src/test/ui/parser/variadic-ffi-3.stderr index 150de9e63d3..8ea4d194396 100644 --- a/src/test/ui/parser/variadic-ffi-3.stderr +++ b/src/test/ui/parser/variadic-ffi-3.stderr @@ -1,4 +1,4 @@ -error: only foreign functions are allowed to be variadic +error: only foreign functions are allowed to be C-variadic --> $DIR/variadic-ffi-3.rs:1:18 | LL | fn foo(x: isize, ...) { diff --git a/src/test/ui/parser/variadic-ffi-4.rs b/src/test/ui/parser/variadic-ffi-4.rs index 812ed256a5d..5f8b3f8f539 100644 --- a/src/test/ui/parser/variadic-ffi-4.rs +++ b/src/test/ui/parser/variadic-ffi-4.rs @@ -1,5 +1,5 @@ extern "C" fn foo(x: isize, ...) { - //~^ ERROR: only foreign functions are allowed to be variadic + //~^ ERROR: only foreign functions are allowed to be C-variadic } fn main() {} diff --git a/src/test/ui/parser/variadic-ffi-4.stderr b/src/test/ui/parser/variadic-ffi-4.stderr index 2d036b0cf37..69fbf84869c 100644 --- a/src/test/ui/parser/variadic-ffi-4.stderr +++ b/src/test/ui/parser/variadic-ffi-4.stderr @@ -1,4 +1,4 @@ -error: only foreign functions are allowed to be variadic +error: only foreign functions are allowed to be C-variadic --> $DIR/variadic-ffi-4.rs:1:29 | LL | extern "C" fn foo(x: isize, ...) { -- cgit 1.4.1-3-g733a5 From dc4973dfd918f5d71cd8e5c8e5aac5b8a86bf4e4 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Fri, 1 Mar 2019 14:42:39 -0800 Subject: Expand where negative supertrait specific error is shown Fix #58857. --- src/libsyntax/parse/parser.rs | 52 +++++++++++++++++++---------------- src/test/ui/issues/issue-58857.rs | 7 +++++ src/test/ui/issues/issue-58857.stderr | 8 ++++++ 3 files changed, 43 insertions(+), 24 deletions(-) create mode 100644 src/test/ui/issues/issue-58857.rs create mode 100644 src/test/ui/issues/issue-58857.stderr (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fd5038a8614..1606bd591bd 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1803,7 +1803,7 @@ impl<'a> Parser<'a> { let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)]; if parse_plus { self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded - bounds.append(&mut self.parse_generic_bounds(None)?); + bounds.append(&mut self.parse_generic_bounds(Some(self.prev_span))?); } Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None)) } @@ -5523,6 +5523,7 @@ impl<'a> Parser<'a> { let mut bounds = Vec::new(); let mut negative_bounds = Vec::new(); let mut last_plus_span = None; + let mut was_negative = false; loop { // This needs to be synchronized with `Token::can_begin_bound`. let is_bound_start = self.check_path() || self.check_lifetime() || @@ -5567,9 +5568,10 @@ impl<'a> Parser<'a> { } let poly_span = lo.to(self.prev_span); if is_negative { - negative_bounds.push( - last_plus_span.or(colon_span).unwrap() - .to(poly_span)); + was_negative = true; + if let Some(sp) = last_plus_span.or(colon_span) { + negative_bounds.push(sp.to(poly_span)); + } } else { let poly_trait = PolyTraitRef::new(lifetime_defs, path, poly_span); let modifier = if question.is_some() { @@ -5591,26 +5593,28 @@ impl<'a> Parser<'a> { } } - if !negative_bounds.is_empty() { + if !negative_bounds.is_empty() || was_negative { let plural = negative_bounds.len() > 1; let mut err = self.struct_span_err(negative_bounds, "negative trait bounds are not supported"); - let bound_list = colon_span.unwrap().to(self.prev_span); - let mut new_bound_list = String::new(); - if !bounds.is_empty() { - let mut snippets = bounds.iter().map(|bound| bound.span()) - .map(|span| self.sess.source_map().span_to_snippet(span)); - while let Some(Ok(snippet)) = snippets.next() { - new_bound_list.push_str(" + "); - new_bound_list.push_str(&snippet); - } - new_bound_list = new_bound_list.replacen(" +", ":", 1); - } - err.span_suggestion_short(bound_list, - &format!("remove the trait bound{}", - if plural { "s" } else { "" }), - new_bound_list, - Applicability::MachineApplicable); + if let Some(bound_list) = colon_span { + let bound_list = bound_list.to(self.prev_span); + let mut new_bound_list = String::new(); + if !bounds.is_empty() { + let mut snippets = bounds.iter().map(|bound| bound.span()) + .map(|span| self.sess.source_map().span_to_snippet(span)); + while let Some(Ok(snippet)) = snippets.next() { + new_bound_list.push_str(" + "); + new_bound_list.push_str(&snippet); + } + new_bound_list = new_bound_list.replacen(" +", ":", 1); + } + err.span_suggestion_short(bound_list, + &format!("remove the trait bound{}", + if plural { "s" } else { "" }), + new_bound_list, + Applicability::MachineApplicable); + } err.emit(); } @@ -5646,7 +5650,7 @@ impl<'a> Parser<'a> { // Parse optional colon and param bounds. let bounds = if self.eat(&token::Colon) { - self.parse_generic_bounds(None)? + self.parse_generic_bounds(Some(self.prev_span))? } else { Vec::new() }; @@ -6091,7 +6095,7 @@ impl<'a> Parser<'a> { // or with mandatory equality sign and the second type. let ty = self.parse_ty()?; if self.eat(&token::Colon) { - let bounds = self.parse_generic_bounds(None)?; + let bounds = self.parse_generic_bounds(Some(self.prev_span))?; where_clause.predicates.push(ast::WherePredicate::BoundPredicate( ast::WhereBoundPredicate { span: lo.to(self.prev_span), @@ -7643,7 +7647,7 @@ impl<'a> Parser<'a> { tps.where_clause = self.parse_where_clause()?; let alias = if existential { self.expect(&token::Colon)?; - let bounds = self.parse_generic_bounds(None)?; + let bounds = self.parse_generic_bounds(Some(self.prev_span))?; AliasKind::Existential(bounds) } else { self.expect(&token::Eq)?; diff --git a/src/test/ui/issues/issue-58857.rs b/src/test/ui/issues/issue-58857.rs new file mode 100644 index 00000000000..392e4ea0c2e --- /dev/null +++ b/src/test/ui/issues/issue-58857.rs @@ -0,0 +1,7 @@ +struct Conj {a : A} +trait Valid {} + +impl Conj{} +//~^ ERROR negative trait bounds are not supported + +fn main() {} diff --git a/src/test/ui/issues/issue-58857.stderr b/src/test/ui/issues/issue-58857.stderr new file mode 100644 index 00000000000..040e9eb8a65 --- /dev/null +++ b/src/test/ui/issues/issue-58857.stderr @@ -0,0 +1,8 @@ +error: negative trait bounds are not supported + --> $DIR/issue-58857.rs:4:7 + | +LL | impl Conj{} + | ^^^^^^^^ help: remove the trait bound + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 2ec7d0b2281e57a456d6122dadd5646804a9d36e Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Fri, 1 Mar 2019 16:28:04 -0800 Subject: Do not panic on missing close paren Fix #58856. --- src/libsyntax/parse/parser.rs | 4 ++- src/test/ui/issues/issue-58856-1.rs | 9 ++++++ src/test/ui/issues/issue-58856-1.stderr | 30 ++++++++++++++++++ src/test/ui/issues/issue-58856-2.rs | 13 ++++++++ src/test/ui/issues/issue-58856-2.stderr | 55 +++++++++++++++++++++++++++++++++ 5 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/issues/issue-58856-1.rs create mode 100644 src/test/ui/issues/issue-58856-1.stderr create mode 100644 src/test/ui/issues/issue-58856-2.rs create mode 100644 src/test/ui/issues/issue-58856-2.stderr (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fd5038a8614..dd4c2393fa5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -6332,8 +6332,10 @@ impl<'a> Parser<'a> { &token::CloseDelim(token::Paren), sep, parse_arg_fn)?; fn_inputs.append(&mut input); (fn_inputs, recovered) + } else if let Err(err) = self.expect_one_of(&[], &[]) { + return Err(err); } else { - return self.unexpected(); + (vec![self_arg], true) } } else { self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)? diff --git a/src/test/ui/issues/issue-58856-1.rs b/src/test/ui/issues/issue-58856-1.rs new file mode 100644 index 00000000000..9311bb0802f --- /dev/null +++ b/src/test/ui/issues/issue-58856-1.rs @@ -0,0 +1,9 @@ +impl A { +//~^ ERROR cannot find type `A` in this scope + fn b(self> + //~^ ERROR expected one of `)`, `,`, or `:`, found `>` + //~| ERROR expected one of `->`, `where`, or `{`, found `>` + //~| ERROR expected one of `->`, `async`, `const`, `crate`, `default`, `existential`, +} + +fn main() {} diff --git a/src/test/ui/issues/issue-58856-1.stderr b/src/test/ui/issues/issue-58856-1.stderr new file mode 100644 index 00000000000..3cbfd375e78 --- /dev/null +++ b/src/test/ui/issues/issue-58856-1.stderr @@ -0,0 +1,30 @@ +error: expected one of `)`, `,`, or `:`, found `>` + --> $DIR/issue-58856-1.rs:3:14 + | +LL | fn b(self> + | - ^ + | | | + | | help: `)` may belong here + | unclosed delimiter + +error: expected one of `->`, `where`, or `{`, found `>` + --> $DIR/issue-58856-1.rs:3:14 + | +LL | fn b(self> + | ^ expected one of `->`, `where`, or `{` here + +error: expected one of `->`, `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, `unsafe`, `where`, or `}`, found `>` + --> $DIR/issue-58856-1.rs:3:14 + | +LL | fn b(self> + | ^ expected one of 13 possible tokens here + +error[E0412]: cannot find type `A` in this scope + --> $DIR/issue-58856-1.rs:1:6 + | +LL | impl A { + | ^ not found in this scope + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/issues/issue-58856-2.rs b/src/test/ui/issues/issue-58856-2.rs new file mode 100644 index 00000000000..4c764761e8e --- /dev/null +++ b/src/test/ui/issues/issue-58856-2.rs @@ -0,0 +1,13 @@ +trait Howness {} +impl Howness for () { + fn how_are_you(&self -> Empty { + //~^ ERROR expected one of `)` or `,`, found `->` + //~| ERROR method `how_are_you` is not a member of trait `Howness` + //~| ERROR cannot find type `Empty` in this scope + Empty + //~^ ERROR cannot find value `Empty` in this scope + } +} +//~^ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, + +fn main() {} diff --git a/src/test/ui/issues/issue-58856-2.stderr b/src/test/ui/issues/issue-58856-2.stderr new file mode 100644 index 00000000000..30027278e23 --- /dev/null +++ b/src/test/ui/issues/issue-58856-2.stderr @@ -0,0 +1,55 @@ +error: expected one of `)` or `,`, found `->` + --> $DIR/issue-58856-2.rs:3:26 + | +LL | fn how_are_you(&self -> Empty { + | - -^^ + | | | + | | help: `)` may belong here + | unclosed delimiter + +error: expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `)` + --> $DIR/issue-58856-2.rs:10:1 + | +LL | } + | - expected one of 11 possible tokens here +LL | } + | ^ unexpected token + +error[E0407]: method `how_are_you` is not a member of trait `Howness` + --> $DIR/issue-58856-2.rs:3:5 + | +LL | / fn how_are_you(&self -> Empty { +LL | | //~^ ERROR expected one of `)` or `,`, found `->` +LL | | //~| ERROR method `how_are_you` is not a member of trait `Howness` +LL | | //~| ERROR cannot find type `Empty` in this scope +LL | | Empty +LL | | //~^ ERROR cannot find value `Empty` in this scope +LL | | } + | |_____^ not a member of trait `Howness` + +error[E0412]: cannot find type `Empty` in this scope + --> $DIR/issue-58856-2.rs:3:29 + | +LL | fn how_are_you(&self -> Empty { + | ^^^^^ not found in this scope +help: possible candidates are found in other modules, you can import them into scope + | +LL | use std::io::Empty; + | +LL | use std::iter::Empty; + | + +error[E0425]: cannot find value `Empty` in this scope + --> $DIR/issue-58856-2.rs:7:9 + | +LL | Empty + | ^^^^^ not found in this scope +help: possible candidate is found in another module, you can import it into scope + | +LL | use std::sync::mpsc::TryRecvError::Empty; + | + +error: aborting due to 5 previous errors + +Some errors occurred: E0407, E0412, E0425. +For more information about an error, try `rustc --explain E0407`. -- cgit 1.4.1-3-g733a5 From cc535a2a19444d7b96e80dc8f445d50452e5495d Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Fri, 1 Mar 2019 21:47:06 -0800 Subject: Bail when encountering a second unexpected token in the same span --- src/libsyntax/parse/parser.rs | 14 +++++++++---- src/test/ui/issues/issue-58856-1.rs | 7 +++---- src/test/ui/issues/issue-58856-1.stderr | 25 +++-------------------- src/test/ui/issues/issue-58856-2.rs | 5 +++-- src/test/ui/issues/issue-58856-2.stderr | 35 +++++---------------------------- src/test/ui/parser/recover-enum2.rs | 3 --- src/test/ui/parser/recover-enum2.stderr | 14 +------------ 7 files changed, 25 insertions(+), 78 deletions(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index dd4c2393fa5..c27a1f79d8c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -46,7 +46,7 @@ use crate::ThinVec; use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; use crate::symbol::{Symbol, keywords}; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError}; use rustc_target::spec::abi::{self, Abi}; use syntax_pos::{Span, MultiSpan, BytePos, FileName}; use log::{debug, trace}; @@ -256,6 +256,7 @@ pub struct Parser<'a> { /// it gets removed from here. Every entry left at the end gets emitted as an independent /// error. crate unclosed_delims: Vec, + last_unexpected_token_span: Option, } @@ -582,6 +583,7 @@ impl<'a> Parser<'a> { unmatched_angle_bracket_count: 0, max_angle_bracket_count: 0, unclosed_delims: Vec::new(), + last_unexpected_token_span: None, }; let tok = parser.next_tok(); @@ -775,6 +777,8 @@ impl<'a> Parser<'a> { } else if inedible.contains(&self.token) { // leave it in the input Ok(false) + } else if self.last_unexpected_token_span == Some(self.span) { + FatalError.raise(); } else { let mut expected = edible.iter() .map(|x| TokenType::Token(x.clone())) @@ -802,6 +806,7 @@ impl<'a> Parser<'a> { (self.sess.source_map().next_point(self.prev_span), format!("expected {} here", expect))) }; + self.last_unexpected_token_span = Some(self.span); let mut err = self.fatal(&msg_exp); if self.token.is_ident_named("and") { err.span_suggestion_short( @@ -6332,10 +6337,11 @@ impl<'a> Parser<'a> { &token::CloseDelim(token::Paren), sep, parse_arg_fn)?; fn_inputs.append(&mut input); (fn_inputs, recovered) - } else if let Err(err) = self.expect_one_of(&[], &[]) { - return Err(err); } else { - (vec![self_arg], true) + match self.expect_one_of(&[], &[]) { + Err(err) => return Err(err), + Ok(recovered) => (vec![self_arg], recovered), + } } } else { self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)? diff --git a/src/test/ui/issues/issue-58856-1.rs b/src/test/ui/issues/issue-58856-1.rs index 9311bb0802f..f5edac0d2e3 100644 --- a/src/test/ui/issues/issue-58856-1.rs +++ b/src/test/ui/issues/issue-58856-1.rs @@ -1,9 +1,8 @@ +struct A; + impl A { -//~^ ERROR cannot find type `A` in this scope - fn b(self> + fn b(self> {} //~^ ERROR expected one of `)`, `,`, or `:`, found `>` - //~| ERROR expected one of `->`, `where`, or `{`, found `>` - //~| ERROR expected one of `->`, `async`, `const`, `crate`, `default`, `existential`, } fn main() {} diff --git a/src/test/ui/issues/issue-58856-1.stderr b/src/test/ui/issues/issue-58856-1.stderr index 3cbfd375e78..85101e467b1 100644 --- a/src/test/ui/issues/issue-58856-1.stderr +++ b/src/test/ui/issues/issue-58856-1.stderr @@ -1,30 +1,11 @@ error: expected one of `)`, `,`, or `:`, found `>` - --> $DIR/issue-58856-1.rs:3:14 + --> $DIR/issue-58856-1.rs:4:14 | -LL | fn b(self> +LL | fn b(self> {} | - ^ | | | | | help: `)` may belong here | unclosed delimiter -error: expected one of `->`, `where`, or `{`, found `>` - --> $DIR/issue-58856-1.rs:3:14 - | -LL | fn b(self> - | ^ expected one of `->`, `where`, or `{` here - -error: expected one of `->`, `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, `unsafe`, `where`, or `}`, found `>` - --> $DIR/issue-58856-1.rs:3:14 - | -LL | fn b(self> - | ^ expected one of 13 possible tokens here - -error[E0412]: cannot find type `A` in this scope - --> $DIR/issue-58856-1.rs:1:6 - | -LL | impl A { - | ^ not found in this scope - -error: aborting due to 4 previous errors +error: aborting due to previous error -For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/issues/issue-58856-2.rs b/src/test/ui/issues/issue-58856-2.rs index 4c764761e8e..acc38e4c201 100644 --- a/src/test/ui/issues/issue-58856-2.rs +++ b/src/test/ui/issues/issue-58856-2.rs @@ -1,11 +1,12 @@ +struct Empty; + trait Howness {} + impl Howness for () { fn how_are_you(&self -> Empty { //~^ ERROR expected one of `)` or `,`, found `->` //~| ERROR method `how_are_you` is not a member of trait `Howness` - //~| ERROR cannot find type `Empty` in this scope Empty - //~^ ERROR cannot find value `Empty` in this scope } } //~^ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, diff --git a/src/test/ui/issues/issue-58856-2.stderr b/src/test/ui/issues/issue-58856-2.stderr index 30027278e23..55a9e9d5cb8 100644 --- a/src/test/ui/issues/issue-58856-2.stderr +++ b/src/test/ui/issues/issue-58856-2.stderr @@ -1,5 +1,5 @@ error: expected one of `)` or `,`, found `->` - --> $DIR/issue-58856-2.rs:3:26 + --> $DIR/issue-58856-2.rs:6:26 | LL | fn how_are_you(&self -> Empty { | - -^^ @@ -8,7 +8,7 @@ LL | fn how_are_you(&self -> Empty { | unclosed delimiter error: expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `)` - --> $DIR/issue-58856-2.rs:10:1 + --> $DIR/issue-58856-2.rs:11:1 | LL | } | - expected one of 11 possible tokens here @@ -16,40 +16,15 @@ LL | } | ^ unexpected token error[E0407]: method `how_are_you` is not a member of trait `Howness` - --> $DIR/issue-58856-2.rs:3:5 + --> $DIR/issue-58856-2.rs:6:5 | LL | / fn how_are_you(&self -> Empty { LL | | //~^ ERROR expected one of `)` or `,`, found `->` LL | | //~| ERROR method `how_are_you` is not a member of trait `Howness` -LL | | //~| ERROR cannot find type `Empty` in this scope LL | | Empty -LL | | //~^ ERROR cannot find value `Empty` in this scope LL | | } | |_____^ not a member of trait `Howness` -error[E0412]: cannot find type `Empty` in this scope - --> $DIR/issue-58856-2.rs:3:29 - | -LL | fn how_are_you(&self -> Empty { - | ^^^^^ not found in this scope -help: possible candidates are found in other modules, you can import them into scope - | -LL | use std::io::Empty; - | -LL | use std::iter::Empty; - | - -error[E0425]: cannot find value `Empty` in this scope - --> $DIR/issue-58856-2.rs:7:9 - | -LL | Empty - | ^^^^^ not found in this scope -help: possible candidate is found in another module, you can import it into scope - | -LL | use std::sync::mpsc::TryRecvError::Empty; - | - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors -Some errors occurred: E0407, E0412, E0425. -For more information about an error, try `rustc --explain E0407`. +For more information about this error, try `rustc --explain E0407`. diff --git a/src/test/ui/parser/recover-enum2.rs b/src/test/ui/parser/recover-enum2.rs index 65a18773787..7f2f2cc7ab0 100644 --- a/src/test/ui/parser/recover-enum2.rs +++ b/src/test/ui/parser/recover-enum2.rs @@ -25,9 +25,6 @@ fn main() { // fail again enum Test4 { Nope(i32 {}) //~ ERROR: found `{` - //~^ ERROR: found `{` } } - // still recover later - let bad_syntax = _; //~ ERROR: expected expression, found reserved identifier `_` } diff --git a/src/test/ui/parser/recover-enum2.stderr b/src/test/ui/parser/recover-enum2.stderr index b308e644ad9..315bfde77c7 100644 --- a/src/test/ui/parser/recover-enum2.stderr +++ b/src/test/ui/parser/recover-enum2.stderr @@ -10,17 +10,5 @@ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `{` LL | Nope(i32 {}) //~ ERROR: found `{` | ^ expected one of 7 possible tokens here -error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `...`, `::`, `<`, `?`, `[`, `_`, `crate`, `dyn`, `extern`, `fn`, `for`, `impl`, `pub`, `unsafe`, `}`, or lifetime, found `{` - --> $DIR/recover-enum2.rs:27:22 - | -LL | Nope(i32 {}) //~ ERROR: found `{` - | ^ expected one of 24 possible tokens here - -error: expected expression, found reserved identifier `_` - --> $DIR/recover-enum2.rs:32:22 - | -LL | let bad_syntax = _; //~ ERROR: expected expression, found reserved identifier `_` - | ^ expected expression - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From ed2de5a8421822ecf9aa3df30bc6c2e55d4ea97d Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Fri, 1 Mar 2019 22:14:22 -0800 Subject: Emit unclosed delimiters during recovery --- src/libsyntax/parse/parser.rs | 1 + src/test/ui/issues/issue-58856-1.rs | 4 ++++ src/test/ui/issues/issue-58856-1.stderr | 10 +++++++++- 3 files changed, 14 insertions(+), 1 deletion(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c27a1f79d8c..0187ad743aa 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -778,6 +778,7 @@ impl<'a> Parser<'a> { // leave it in the input Ok(false) } else if self.last_unexpected_token_span == Some(self.span) { + emit_unclosed_delims(&self.unclosed_delims, self.diagnostic()); FatalError.raise(); } else { let mut expected = edible.iter() diff --git a/src/test/ui/issues/issue-58856-1.rs b/src/test/ui/issues/issue-58856-1.rs index f5edac0d2e3..7dc3658776e 100644 --- a/src/test/ui/issues/issue-58856-1.rs +++ b/src/test/ui/issues/issue-58856-1.rs @@ -5,4 +5,8 @@ impl A { //~^ ERROR expected one of `)`, `,`, or `:`, found `>` } +// verify that mismatched delimiters get emitted +fn foo(] {} +//~^ ERROR incorrect close delimiter + fn main() {} diff --git a/src/test/ui/issues/issue-58856-1.stderr b/src/test/ui/issues/issue-58856-1.stderr index 85101e467b1..f26ebbe15c5 100644 --- a/src/test/ui/issues/issue-58856-1.stderr +++ b/src/test/ui/issues/issue-58856-1.stderr @@ -7,5 +7,13 @@ LL | fn b(self> {} | | help: `)` may belong here | unclosed delimiter -error: aborting due to previous error +error: incorrect close delimiter: `]` + --> $DIR/issue-58856-1.rs:9:8 + | +LL | fn foo(] {} + | -^ incorrect close delimiter + | | + | un-closed delimiter + +error: aborting due to 2 previous errors -- cgit 1.4.1-3-g733a5 From c70a516c23ae19ce568166a81e64c92a4ecf540a Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 3 Mar 2019 11:13:19 -0800 Subject: Panic when unmatched delimiters aren't emitted --- src/libsyntax/ext/tt/macro_parser.rs | 2 +- src/libsyntax/parse/parser.rs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index fe1cffb092b..1a419e7fada 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -761,7 +761,7 @@ pub fn parse( else if bb_items.is_empty() && next_items.is_empty() { return Failure( parser.span, - parser.token, + parser.token.clone(), "no rules expected this token in macro call", ); } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 0187ad743aa..33fe81ea8c4 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -259,6 +259,13 @@ pub struct Parser<'a> { last_unexpected_token_span: Option, } +impl<'a> Drop for Parser<'a> { + fn drop(&mut self) { + if !self.unclosed_delims.is_empty() { + panic!("unclosed delimiter errors not emitted"); + } + } +} #[derive(Clone)] struct TokenCursor { -- cgit 1.4.1-3-g733a5 From 51d0e86c221dbd937ca248f25a95dad787035b9e Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 3 Mar 2019 12:14:25 -0800 Subject: Emit missing unclosed delimiter errors --- src/librustc_metadata/cstore_impl.rs | 4 +- src/libsyntax/parse/parser.rs | 14 ++++--- src/libsyntax/parse/token.rs | 12 +++--- src/libsyntax_ext/proc_macro_server.rs | 4 +- src/test/ui/parser-recovery-2.stderr | 12 +++--- src/test/ui/resolve/token-error-correct-3.rs | 16 ++++---- src/test/ui/resolve/token-error-correct-3.stderr | 49 ++++++++++++------------ 7 files changed, 56 insertions(+), 55 deletions(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index f49b88f14e6..67a249e605e 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -439,8 +439,8 @@ impl cstore::CStore { let source_file = sess.parse_sess.source_map().new_source_file(source_name, def.body); let local_span = Span::new(source_file.start_pos, source_file.end_pos, NO_EXPANSION); - let (body, errors) = source_file_to_stream(&sess.parse_sess, source_file, None); - emit_unclosed_delims(&errors, &sess.diagnostic()); + let (body, mut errors) = source_file_to_stream(&sess.parse_sess, source_file, None); + emit_unclosed_delims(&mut errors, &sess.diagnostic()); // Mark the attrs as used let attrs = data.get_item_attrs(id.index, sess); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 33fe81ea8c4..bde14e192e9 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -7798,7 +7798,10 @@ impl<'a> Parser<'a> { attributes_allowed: bool, ) -> PResult<'a, Option>> { let (ret, tokens) = self.collect_tokens(|this| { - this.parse_item_implementation(attrs, macros_allowed, attributes_allowed) + let item = this.parse_item_implementation(attrs, macros_allowed, attributes_allowed); + let diag = this.diagnostic(); + emit_unclosed_delims(&mut this.unclosed_delims, diag); + item })?; // Once we've parsed an item and recorded the tokens we got while @@ -8555,8 +8558,8 @@ impl<'a> Parser<'a> { module: self.parse_mod_items(&token::Eof, lo)?, span: lo.to(self.span), }); - emit_unclosed_delims(&self.unclosed_delims, self.diagnostic()); - self.unclosed_delims.clear(); + let diag = self.diagnostic(); + emit_unclosed_delims(&mut self.unclosed_delims, diag); krate } @@ -8587,8 +8590,8 @@ impl<'a> Parser<'a> { } } -pub fn emit_unclosed_delims(unclosed_delims: &[UnmatchedBrace], handler: &errors::Handler) { - for unmatched in unclosed_delims { +pub fn emit_unclosed_delims(unclosed_delims: &mut Vec, handler: &errors::Handler) { + for unmatched in unclosed_delims.iter() { let mut err = handler.struct_span_err(unmatched.found_span, &format!( "incorrect close delimiter: `{}`", pprust::token_to_string(&token::Token::CloseDelim(unmatched.found_delim)), @@ -8602,4 +8605,5 @@ pub fn emit_unclosed_delims(unclosed_delims: &[UnmatchedBrace], handler: &errors } err.emit(); } + unclosed_delims.clear(); } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index eec422d6266..bb4da12bae8 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -675,9 +675,9 @@ impl Nonterminal { // FIXME(#43081): Avoid this pretty-print + reparse hack let source = pprust::nonterminal_to_string(self); let filename = FileName::macro_expansion_source_code(&source); - let (tokens_for_real, errors) = + let (tokens_for_real, mut errors) = parse_stream_from_source_str(filename, source, sess, Some(span)); - emit_unclosed_delims(&errors, &sess.span_diagnostic); + emit_unclosed_delims(&mut errors, &sess.span_diagnostic); // During early phases of the compiler the AST could get modified // directly (e.g., attributes added or removed) and the internal cache @@ -740,13 +740,13 @@ fn prepend_attrs(sess: &ParseSess, let source = pprust::attr_to_string(attr); let macro_filename = FileName::macro_expansion_source_code(&source); if attr.is_sugared_doc { - let (stream, errors) = parse_stream_from_source_str( + let (stream, mut errors) = parse_stream_from_source_str( macro_filename, source, sess, Some(span), ); - emit_unclosed_delims(&errors, &sess.span_diagnostic); + emit_unclosed_delims(&mut errors, &sess.span_diagnostic); builder.push(stream); continue } @@ -763,13 +763,13 @@ fn prepend_attrs(sess: &ParseSess, // ... and for more complicated paths, fall back to a reparse hack that // should eventually be removed. } else { - let (stream, errors) = parse_stream_from_source_str( + let (stream, mut errors) = parse_stream_from_source_str( macro_filename, source, sess, Some(span), ); - emit_unclosed_delims(&errors, &sess.span_diagnostic); + emit_unclosed_delims(&mut errors, &sess.span_diagnostic); brackets.push(stream); } diff --git a/src/libsyntax_ext/proc_macro_server.rs b/src/libsyntax_ext/proc_macro_server.rs index 4c4b33c0442..5822b5607f7 100644 --- a/src/libsyntax_ext/proc_macro_server.rs +++ b/src/libsyntax_ext/proc_macro_server.rs @@ -410,13 +410,13 @@ impl server::TokenStream for Rustc<'_> { stream.is_empty() } fn from_str(&mut self, src: &str) -> Self::TokenStream { - let (tokens, errors) = parse::parse_stream_from_source_str( + let (tokens, mut errors) = parse::parse_stream_from_source_str( FileName::proc_macro_source_code(src.clone()), src.to_string(), self.sess, Some(self.call_site), ); - emit_unclosed_delims(&errors, &self.sess.span_diagnostic); + emit_unclosed_delims(&mut errors, &self.sess.span_diagnostic); tokens } fn to_string(&mut self, stream: &Self::TokenStream) -> String { diff --git a/src/test/ui/parser-recovery-2.stderr b/src/test/ui/parser-recovery-2.stderr index 76f7af38e77..92d8cbc100a 100644 --- a/src/test/ui/parser-recovery-2.stderr +++ b/src/test/ui/parser-recovery-2.stderr @@ -1,9 +1,3 @@ -error: unexpected token: `;` - --> $DIR/parser-recovery-2.rs:12:15 - | -LL | let x = y.; //~ ERROR unexpected token - | ^ - error: incorrect close delimiter: `)` --> $DIR/parser-recovery-2.rs:8:5 | @@ -13,6 +7,12 @@ LL | let x = foo(); //~ ERROR cannot find function `foo` in this scope LL | ) //~ ERROR incorrect close delimiter: `)` | ^ incorrect close delimiter +error: unexpected token: `;` + --> $DIR/parser-recovery-2.rs:12:15 + | +LL | let x = y.; //~ ERROR unexpected token + | ^ + error[E0425]: cannot find function `foo` in this scope --> $DIR/parser-recovery-2.rs:7:17 | diff --git a/src/test/ui/resolve/token-error-correct-3.rs b/src/test/ui/resolve/token-error-correct-3.rs index b1ca0bbfc57..05bdbeacf72 100644 --- a/src/test/ui/resolve/token-error-correct-3.rs +++ b/src/test/ui/resolve/token-error-correct-3.rs @@ -10,16 +10,14 @@ pub mod raw { pub fn ensure_dir_exists, F: FnOnce(&Path)>(path: P, callback: F) -> io::Result { - if !is_directory(path.as_ref()) { //~ ERROR: cannot find function `is_directory` - callback(path.as_ref(); //~ ERROR expected one of - fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types - //~^ expected (), found enum `std::result::Result` - //~| expected type `()` - //~| found type `std::result::Result` - //~| expected one of + if !is_directory(path.as_ref()) { + //~^ ERROR cannot find function `is_directory` + callback(path.as_ref(); + //~^ ERROR expected one of + //~| ERROR this function takes 1 parameter but 2 parameters were supplied + fs::create_dir_all(path.as_ref()).map(|()| true) } else { - //~^ ERROR: expected one of - //~| unexpected token + //~^ ERROR incorrect close delimiter: `}` Ok(false); } diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index a6bb83c71f3..0f1cbd6c2f7 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -1,39 +1,38 @@ -error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;` - --> $DIR/token-error-correct-3.rs:14:35 - | -LL | callback(path.as_ref(); //~ ERROR expected one of - | - ^ - | | | - | | help: `)` may belong here - | unclosed delimiter - -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` - --> $DIR/token-error-correct-3.rs:20:9 +error: incorrect close delimiter: `}` + --> $DIR/token-error-correct-3.rs:19:9 | -LL | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types - | - expected one of `.`, `;`, `?`, `}`, or an operator here +LL | if !is_directory(path.as_ref()) { + | - close delimiter possibly meant for this +LL | //~^ ERROR cannot find function `is_directory` +LL | callback(path.as_ref(); + | - un-closed delimiter ... LL | } else { - | ^ unexpected token + | ^ incorrect close delimiter + +error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;` + --> $DIR/token-error-correct-3.rs:15:35 + | +LL | callback(path.as_ref(); + | ^ expected one of `)`, `,`, `.`, `?`, or an operator here error[E0425]: cannot find function `is_directory` in this scope --> $DIR/token-error-correct-3.rs:13:13 | -LL | if !is_directory(path.as_ref()) { //~ ERROR: cannot find function `is_directory` +LL | if !is_directory(path.as_ref()) { | ^^^^^^^^^^^^ not found in this scope -error[E0308]: mismatched types +error[E0057]: this function takes 1 parameter but 2 parameters were supplied --> $DIR/token-error-correct-3.rs:15:13 | -LL | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon: `;` - | | - | expected (), found enum `std::result::Result` - | - = note: expected type `()` - found type `std::result::Result` +LL | / callback(path.as_ref(); +LL | | //~^ ERROR expected one of +LL | | //~| ERROR this function takes 1 parameter but 2 parameters were supplied +LL | | fs::create_dir_all(path.as_ref()).map(|()| true) +LL | | } else { + | |_________^ expected 1 parameter error: aborting due to 4 previous errors -Some errors occurred: E0308, E0425. -For more information about an error, try `rustc --explain E0308`. +Some errors occurred: E0057, E0425. +For more information about an error, try `rustc --explain E0057`. -- cgit 1.4.1-3-g733a5 From ac6cc2d6b0aad0b1cc97f1db6d8e9d4f117eca95 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 3 Mar 2019 12:45:49 -0800 Subject: Collect unclosed delimiters in parent parser --- src/libsyntax/parse/parser.rs | 17 +++++++-- src/test/ui/parser-recovery-2.stderr | 12 +++--- src/test/ui/resolve/token-error-correct-3.rs | 4 +- src/test/ui/resolve/token-error-correct-3.stderr | 47 ++++++++++++------------ 4 files changed, 45 insertions(+), 35 deletions(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index bde14e192e9..348c26d2044 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1510,9 +1510,13 @@ impl<'a> Parser<'a> { pub fn parse_trait_item(&mut self, at_end: &mut bool) -> PResult<'a, TraitItem> { maybe_whole!(self, NtTraitItem, |x| x); let attrs = self.parse_outer_attributes()?; + let mut unclosed_delims = vec![]; let (mut item, tokens) = self.collect_tokens(|this| { - this.parse_trait_item_(at_end, attrs) + let item = this.parse_trait_item_(at_end, attrs); + unclosed_delims.append(&mut this.unclosed_delims); + item })?; + self.unclosed_delims.append(&mut unclosed_delims); // See `parse_item` for why this clause is here. if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { item.tokens = Some(tokens); @@ -6475,9 +6479,13 @@ impl<'a> Parser<'a> { pub fn parse_impl_item(&mut self, at_end: &mut bool) -> PResult<'a, ImplItem> { maybe_whole!(self, NtImplItem, |x| x); let attrs = self.parse_outer_attributes()?; + let mut unclosed_delims = vec![]; let (mut item, tokens) = self.collect_tokens(|this| { - this.parse_impl_item_(at_end, attrs) + let item = this.parse_impl_item_(at_end, attrs); + unclosed_delims.append(&mut this.unclosed_delims); + item })?; + self.unclosed_delims.append(&mut unclosed_delims); // See `parse_item` for why this clause is here. if !item.attrs.iter().any(|attr| attr.style == AttrStyle::Inner) { @@ -7797,12 +7805,13 @@ impl<'a> Parser<'a> { macros_allowed: bool, attributes_allowed: bool, ) -> PResult<'a, Option>> { + let mut unclosed_delims = vec![]; let (ret, tokens) = self.collect_tokens(|this| { let item = this.parse_item_implementation(attrs, macros_allowed, attributes_allowed); - let diag = this.diagnostic(); - emit_unclosed_delims(&mut this.unclosed_delims, diag); + unclosed_delims.append(&mut this.unclosed_delims); item })?; + self.unclosed_delims.append(&mut unclosed_delims); // Once we've parsed an item and recorded the tokens we got while // parsing we may want to store `tokens` into the item we're about to diff --git a/src/test/ui/parser-recovery-2.stderr b/src/test/ui/parser-recovery-2.stderr index 92d8cbc100a..76f7af38e77 100644 --- a/src/test/ui/parser-recovery-2.stderr +++ b/src/test/ui/parser-recovery-2.stderr @@ -1,3 +1,9 @@ +error: unexpected token: `;` + --> $DIR/parser-recovery-2.rs:12:15 + | +LL | let x = y.; //~ ERROR unexpected token + | ^ + error: incorrect close delimiter: `)` --> $DIR/parser-recovery-2.rs:8:5 | @@ -7,12 +13,6 @@ LL | let x = foo(); //~ ERROR cannot find function `foo` in this scope LL | ) //~ ERROR incorrect close delimiter: `)` | ^ incorrect close delimiter -error: unexpected token: `;` - --> $DIR/parser-recovery-2.rs:12:15 - | -LL | let x = y.; //~ ERROR unexpected token - | ^ - error[E0425]: cannot find function `foo` in this scope --> $DIR/parser-recovery-2.rs:7:17 | diff --git a/src/test/ui/resolve/token-error-correct-3.rs b/src/test/ui/resolve/token-error-correct-3.rs index 05bdbeacf72..212b88ac8b0 100644 --- a/src/test/ui/resolve/token-error-correct-3.rs +++ b/src/test/ui/resolve/token-error-correct-3.rs @@ -14,10 +14,10 @@ pub mod raw { //~^ ERROR cannot find function `is_directory` callback(path.as_ref(); //~^ ERROR expected one of - //~| ERROR this function takes 1 parameter but 2 parameters were supplied fs::create_dir_all(path.as_ref()).map(|()| true) + //~^ ERROR mismatched types } else { - //~^ ERROR incorrect close delimiter: `}` + //~^ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `)` Ok(false); } diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index 0f1cbd6c2f7..035a5ede453 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -1,20 +1,20 @@ -error: incorrect close delimiter: `}` - --> $DIR/token-error-correct-3.rs:19:9 - | -LL | if !is_directory(path.as_ref()) { - | - close delimiter possibly meant for this -LL | //~^ ERROR cannot find function `is_directory` -LL | callback(path.as_ref(); - | - un-closed delimiter -... -LL | } else { - | ^ incorrect close delimiter - error: expected one of `)`, `,`, `.`, `?`, or an operator, found `;` --> $DIR/token-error-correct-3.rs:15:35 | LL | callback(path.as_ref(); - | ^ expected one of `)`, `,`, `.`, `?`, or an operator here + | - ^ + | | | + | | help: `)` may belong here + | unclosed delimiter + +error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` + --> $DIR/token-error-correct-3.rs:19:9 + | +LL | fs::create_dir_all(path.as_ref()).map(|()| true) + | - expected one of `.`, `;`, `?`, `}`, or an operator here +LL | //~^ ERROR mismatched types +LL | } else { + | ^ unexpected token error[E0425]: cannot find function `is_directory` in this scope --> $DIR/token-error-correct-3.rs:13:13 @@ -22,17 +22,18 @@ error[E0425]: cannot find function `is_directory` in this scope LL | if !is_directory(path.as_ref()) { | ^^^^^^^^^^^^ not found in this scope -error[E0057]: this function takes 1 parameter but 2 parameters were supplied - --> $DIR/token-error-correct-3.rs:15:13 +error[E0308]: mismatched types + --> $DIR/token-error-correct-3.rs:17:13 + | +LL | fs::create_dir_all(path.as_ref()).map(|()| true) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon: `;` + | | + | expected (), found enum `std::result::Result` | -LL | / callback(path.as_ref(); -LL | | //~^ ERROR expected one of -LL | | //~| ERROR this function takes 1 parameter but 2 parameters were supplied -LL | | fs::create_dir_all(path.as_ref()).map(|()| true) -LL | | } else { - | |_________^ expected 1 parameter + = note: expected type `()` + found type `std::result::Result` error: aborting due to 4 previous errors -Some errors occurred: E0057, E0425. -For more information about an error, try `rustc --explain E0057`. +Some errors occurred: E0308, E0425. +For more information about an error, try `rustc --explain E0308`. -- cgit 1.4.1-3-g733a5 From f156d9220703d99709be32ea1be0be0d44535114 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 3 Mar 2019 14:11:41 -0800 Subject: Always emit mismatched delim errors, never panic --- src/libsyntax/parse/parser.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 348c26d2044..860964a736f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -262,7 +262,8 @@ pub struct Parser<'a> { impl<'a> Drop for Parser<'a> { fn drop(&mut self) { if !self.unclosed_delims.is_empty() { - panic!("unclosed delimiter errors not emitted"); + let diag = self.diagnostic(); + emit_unclosed_delims(&mut self.unclosed_delims, diag); } } } @@ -8567,8 +8568,6 @@ impl<'a> Parser<'a> { module: self.parse_mod_items(&token::Eof, lo)?, span: lo.to(self.span), }); - let diag = self.diagnostic(); - emit_unclosed_delims(&mut self.unclosed_delims, diag); krate } -- cgit 1.4.1-3-g733a5 From 6f0f2fc6d6ca0800c8b8b95932010d51af4e4663 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Mon, 4 Mar 2019 12:59:43 -0800 Subject: Simplify code --- src/libsyntax/parse/mod.rs | 11 +++++++++-- src/libsyntax/parse/parser.rs | 6 ++---- src/libsyntax/parse/token.rs | 21 +++------------------ src/libsyntax_ext/proc_macro_server.rs | 7 ++----- 4 files changed, 16 insertions(+), 29 deletions(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b2d4d97d57d..6583458b446 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -6,6 +6,7 @@ use crate::source_map::{SourceMap, FilePathMapping}; use crate::feature_gate::UnstableFeatures; use crate::parse::parser::Parser; use crate::symbol::Symbol; +use crate::syntax::parse::parser::emit_unclosed_delims; use crate::tokenstream::{TokenStream, TokenTree}; use crate::diagnostics::plugin::ErrorMap; use crate::print::pprust::token_to_string; @@ -141,8 +142,14 @@ pub fn parse_stream_from_source_str( source: String, sess: &ParseSess, override_span: Option, -) -> (TokenStream, Vec) { - source_file_to_stream(sess, sess.source_map().new_source_file(name, source), override_span) +) -> TokenStream { + let (stream, mut errors) = source_file_to_stream( + sess, + sess.source_map().new_source_file(name, source), + override_span, + ); + emit_unclosed_delims(&mut errors, &sess.span_diagnostic); + stream } /// Creates a new parser from a source string. diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 860964a736f..58c1c5006bb 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -261,10 +261,8 @@ pub struct Parser<'a> { impl<'a> Drop for Parser<'a> { fn drop(&mut self) { - if !self.unclosed_delims.is_empty() { - let diag = self.diagnostic(); - emit_unclosed_delims(&mut self.unclosed_delims, diag); - } + let diag = self.diagnostic(); + emit_unclosed_delims(&mut self.unclosed_delims, diag); } } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index bb4da12bae8..2fa4f5263fb 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -10,7 +10,6 @@ use crate::print::pprust; use crate::ptr::P; use crate::symbol::keywords; use crate::syntax::parse::parse_stream_from_source_str; -use crate::syntax::parse::parser::emit_unclosed_delims; use crate::tokenstream::{self, DelimSpan, TokenStream, TokenTree}; use syntax_pos::symbol::{self, Symbol}; @@ -675,9 +674,7 @@ impl Nonterminal { // FIXME(#43081): Avoid this pretty-print + reparse hack let source = pprust::nonterminal_to_string(self); let filename = FileName::macro_expansion_source_code(&source); - let (tokens_for_real, mut errors) = - parse_stream_from_source_str(filename, source, sess, Some(span)); - emit_unclosed_delims(&mut errors, &sess.span_diagnostic); + let tokens_for_real = parse_stream_from_source_str(filename, source, sess, Some(span)); // During early phases of the compiler the AST could get modified // directly (e.g., attributes added or removed) and the internal cache @@ -740,13 +737,7 @@ fn prepend_attrs(sess: &ParseSess, let source = pprust::attr_to_string(attr); let macro_filename = FileName::macro_expansion_source_code(&source); if attr.is_sugared_doc { - let (stream, mut errors) = parse_stream_from_source_str( - macro_filename, - source, - sess, - Some(span), - ); - emit_unclosed_delims(&mut errors, &sess.span_diagnostic); + let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span)); builder.push(stream); continue } @@ -763,13 +754,7 @@ fn prepend_attrs(sess: &ParseSess, // ... and for more complicated paths, fall back to a reparse hack that // should eventually be removed. } else { - let (stream, mut errors) = parse_stream_from_source_str( - macro_filename, - source, - sess, - Some(span), - ); - emit_unclosed_delims(&mut errors, &sess.span_diagnostic); + let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span)); brackets.push(stream); } diff --git a/src/libsyntax_ext/proc_macro_server.rs b/src/libsyntax_ext/proc_macro_server.rs index 5822b5607f7..a7ac95ba9ef 100644 --- a/src/libsyntax_ext/proc_macro_server.rs +++ b/src/libsyntax_ext/proc_macro_server.rs @@ -12,7 +12,6 @@ use syntax::ast; use syntax::ext::base::ExtCtxt; use syntax::parse::lexer::comments; use syntax::parse::{self, token, ParseSess}; -use syntax::parse::parser::emit_unclosed_delims; use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint}; use syntax_pos::hygiene::{SyntaxContext, Transparency}; use syntax_pos::symbol::{keywords, Symbol}; @@ -410,14 +409,12 @@ impl server::TokenStream for Rustc<'_> { stream.is_empty() } fn from_str(&mut self, src: &str) -> Self::TokenStream { - let (tokens, mut errors) = parse::parse_stream_from_source_str( + parse::parse_stream_from_source_str( FileName::proc_macro_source_code(src.clone()), src.to_string(), self.sess, Some(self.call_site), - ); - emit_unclosed_delims(&mut errors, &self.sess.span_diagnostic); - tokens + ) } fn to_string(&mut self, stream: &Self::TokenStream) -> String { stream.to_string() -- cgit 1.4.1-3-g733a5 From 551ea65c87ef567cb22856a769df2a75f2cbb235 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Wed, 6 Mar 2019 19:09:24 -0800 Subject: Rely on drop to emit unclosed delims --- src/libsyntax/parse/parser.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'src/libsyntax/parse/parser.rs') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 58c1c5006bb..7e63da27049 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -784,7 +784,6 @@ impl<'a> Parser<'a> { // leave it in the input Ok(false) } else if self.last_unexpected_token_span == Some(self.span) { - emit_unclosed_delims(&self.unclosed_delims, self.diagnostic()); FatalError.raise(); } else { let mut expected = edible.iter() -- cgit 1.4.1-3-g733a5