Auto merge of #69919 - Centril:rollup-fxo33zs, r=Centril
Rollup of 8 pull requests Successful merges: - #66472 (--show-coverage json) - #69603 (tidy: replace `make check` with `./x.py test` in documentation) - #69760 (Improve expression & attribute parsing) - #69828 (fix memory leak when vec::IntoIter panics during drop) - #69850 (panic_bounds_check: use caller_location, like PanicFnLangItem) - #69876 (Add long error explanation for E0739) - #69888 ([Miri] Use a session variable instead of checking for an env var always) - #69893 (librustc_codegen_llvm: Use slices instead of 0-terminated strings) Failed merges: r? @ghost
This commit is contained in:
commit
c20d7eecbc
92 changed files with 1264 additions and 513 deletions
|
@ -142,7 +142,7 @@ the issue in question.
|
||||||
Please make sure your pull request is in compliance with Rust's style
|
Please make sure your pull request is in compliance with Rust's style
|
||||||
guidelines by running
|
guidelines by running
|
||||||
|
|
||||||
$ python x.py test src/tools/tidy
|
$ python x.py test tidy
|
||||||
|
|
||||||
Make this check before every pull request (and every new commit in a pull
|
Make this check before every pull request (and every new commit in a pull
|
||||||
request); you can add [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks)
|
request); you can add [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks)
|
||||||
|
|
|
@ -55,6 +55,9 @@ The script accepts commands, flags, and arguments to determine what to do:
|
||||||
# run all unit tests
|
# run all unit tests
|
||||||
./x.py test
|
./x.py test
|
||||||
|
|
||||||
|
# execute tool tests
|
||||||
|
./x.py test tidy
|
||||||
|
|
||||||
# execute the UI test suite
|
# execute the UI test suite
|
||||||
./x.py test src/test/ui
|
./x.py test src/test/ui
|
||||||
|
|
||||||
|
|
|
@ -359,7 +359,7 @@ Arguments:
|
||||||
subcommand_help.push_str(
|
subcommand_help.push_str(
|
||||||
"\n
|
"\n
|
||||||
Arguments:
|
Arguments:
|
||||||
This subcommand accepts a number of paths to directories to tests that
|
This subcommand accepts a number of paths to test directories that
|
||||||
should be compiled and run. For example:
|
should be compiled and run. For example:
|
||||||
|
|
||||||
./x.py test src/test/ui
|
./x.py test src/test/ui
|
||||||
|
@ -372,6 +372,10 @@ Arguments:
|
||||||
just like `build src/libstd --stage N` it tests the compiler produced by the previous
|
just like `build src/libstd --stage N` it tests the compiler produced by the previous
|
||||||
stage.
|
stage.
|
||||||
|
|
||||||
|
Execute tool tests with a tool name argument:
|
||||||
|
|
||||||
|
./x.py test tidy
|
||||||
|
|
||||||
If no arguments are passed then the complete artifacts for that stage are
|
If no arguments are passed then the complete artifacts for that stage are
|
||||||
compiled and tested.
|
compiled and tested.
|
||||||
|
|
||||||
|
|
|
@ -2626,13 +2626,21 @@ impl<T: Clone> Clone for IntoIter<T> {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
unsafe impl<#[may_dangle] T> Drop for IntoIter<T> {
|
unsafe impl<#[may_dangle] T> Drop for IntoIter<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// destroy the remaining elements
|
struct DropGuard<'a, T>(&'a mut IntoIter<T>);
|
||||||
unsafe {
|
|
||||||
ptr::drop_in_place(self.as_mut_slice());
|
impl<T> Drop for DropGuard<'_, T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// RawVec handles deallocation
|
||||||
|
let _ = unsafe { RawVec::from_raw_parts(self.0.buf.as_ptr(), self.0.cap) };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RawVec handles deallocation
|
let guard = DropGuard(self);
|
||||||
let _ = unsafe { RawVec::from_raw_parts(self.buf.as_ptr(), self.cap) };
|
// destroy the remaining elements
|
||||||
|
unsafe {
|
||||||
|
ptr::drop_in_place(guard.0.as_mut_slice());
|
||||||
|
}
|
||||||
|
// now `guard` will be dropped and do the rest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#[cfg(bootstrap)]
|
||||||
#[doc(include = "panic.md")]
|
#[doc(include = "panic.md")]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[allow_internal_unstable(core_panic, track_caller)]
|
#[allow_internal_unstable(core_panic, track_caller)]
|
||||||
|
@ -20,6 +21,26 @@ macro_rules! panic {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
#[doc(include = "panic.md")]
|
||||||
|
#[macro_export]
|
||||||
|
#[allow_internal_unstable(core_panic, track_caller)]
|
||||||
|
#[stable(feature = "core", since = "1.6.0")]
|
||||||
|
macro_rules! panic {
|
||||||
|
() => (
|
||||||
|
$crate::panic!("explicit panic")
|
||||||
|
);
|
||||||
|
($msg:expr) => (
|
||||||
|
$crate::panicking::panic($msg)
|
||||||
|
);
|
||||||
|
($msg:expr,) => (
|
||||||
|
$crate::panic!($msg)
|
||||||
|
);
|
||||||
|
($fmt:expr, $($arg:tt)+) => (
|
||||||
|
$crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Asserts that two expressions are equal to each other (using [`PartialEq`]).
|
/// Asserts that two expressions are equal to each other (using [`PartialEq`]).
|
||||||
///
|
///
|
||||||
/// On panic, this macro will print the values of the expressions with their
|
/// On panic, this macro will print the values of the expressions with their
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
use crate::fmt;
|
use crate::fmt;
|
||||||
use crate::panic::{Location, PanicInfo};
|
use crate::panic::{Location, PanicInfo};
|
||||||
|
|
||||||
|
/// The underlying implementation of libcore's `panic!` macro when no formatting is used.
|
||||||
#[cold]
|
#[cold]
|
||||||
// never inline unless panic_immediate_abort to avoid code
|
// never inline unless panic_immediate_abort to avoid code
|
||||||
// bloat at the call sites as much as possible
|
// bloat at the call sites as much as possible
|
||||||
|
@ -49,9 +50,28 @@ pub fn panic(expr: &str) -> ! {
|
||||||
// truncation and padding (even though none is used here). Using
|
// truncation and padding (even though none is used here). Using
|
||||||
// Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
|
// Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
|
||||||
// output binary, saving up to a few kilobytes.
|
// output binary, saving up to a few kilobytes.
|
||||||
panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), Location::caller())
|
#[cfg(not(bootstrap))]
|
||||||
|
panic_fmt(fmt::Arguments::new_v1(&[expr], &[]));
|
||||||
|
#[cfg(bootstrap)]
|
||||||
|
panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), Location::caller());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
#[cold]
|
||||||
|
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||||
|
#[track_caller]
|
||||||
|
#[lang = "panic_bounds_check"] // needed by codegen for panic on OOB array/slice access
|
||||||
|
fn panic_bounds_check(index: usize, len: usize) -> ! {
|
||||||
|
if cfg!(feature = "panic_immediate_abort") {
|
||||||
|
unsafe { super::intrinsics::abort() }
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("index out of bounds: the len is {} but the index is {}", len, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// For bootstrap, we need a variant with the old argument order, and a corresponding
|
||||||
|
// `panic_fmt`.
|
||||||
|
#[cfg(bootstrap)]
|
||||||
#[cold]
|
#[cold]
|
||||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||||
#[lang = "panic_bounds_check"] // needed by codegen for panic on OOB array/slice access
|
#[lang = "panic_bounds_check"] // needed by codegen for panic on OOB array/slice access
|
||||||
|
@ -66,10 +86,12 @@ fn panic_bounds_check(location: &Location<'_>, index: usize, len: usize) -> ! {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The underlying implementation of libcore's `panic!` macro when formatting is used.
|
||||||
#[cold]
|
#[cold]
|
||||||
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||||
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
#[cfg_attr(feature = "panic_immediate_abort", inline)]
|
||||||
pub fn panic_fmt(fmt: fmt::Arguments<'_>, location: &Location<'_>) -> ! {
|
#[cfg_attr(not(bootstrap), track_caller)]
|
||||||
|
pub fn panic_fmt(fmt: fmt::Arguments<'_>, #[cfg(bootstrap)] location: &Location<'_>) -> ! {
|
||||||
if cfg!(feature = "panic_immediate_abort") {
|
if cfg!(feature = "panic_immediate_abort") {
|
||||||
unsafe { super::intrinsics::abort() }
|
unsafe { super::intrinsics::abort() }
|
||||||
}
|
}
|
||||||
|
@ -81,6 +103,10 @@ pub fn panic_fmt(fmt: fmt::Arguments<'_>, location: &Location<'_>) -> ! {
|
||||||
fn panic_impl(pi: &PanicInfo<'_>) -> !;
|
fn panic_impl(pi: &PanicInfo<'_>) -> !;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(bootstrap)]
|
||||||
let pi = PanicInfo::internal_constructor(Some(&fmt), location);
|
let pi = PanicInfo::internal_constructor(Some(&fmt), location);
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller());
|
||||||
|
|
||||||
unsafe { panic_impl(&pi) }
|
unsafe { panic_impl(&pi) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,18 @@ use crate::mir;
|
||||||
use crate::mir::interpret::ConstValue;
|
use crate::mir::interpret::ConstValue;
|
||||||
use crate::ty::layout::{Align, LayoutError, Size};
|
use crate::ty::layout::{Align, LayoutError, Size};
|
||||||
use crate::ty::query::TyCtxtAt;
|
use crate::ty::query::TyCtxtAt;
|
||||||
|
use crate::ty::tls;
|
||||||
use crate::ty::{self, layout, Ty};
|
use crate::ty::{self, layout, Ty};
|
||||||
|
|
||||||
use backtrace::Backtrace;
|
use backtrace::Backtrace;
|
||||||
|
use rustc_data_structures::sync::Lock;
|
||||||
use rustc_errors::{struct_span_err, DiagnosticBuilder};
|
use rustc_errors::{struct_span_err, DiagnosticBuilder};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
|
use rustc_session::CtfeBacktrace;
|
||||||
use rustc_span::{Pos, Span};
|
use rustc_span::{Pos, Span};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use std::{any::Any, env, fmt};
|
use std::{any::Any, fmt};
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)]
|
||||||
pub enum ErrorHandled {
|
pub enum ErrorHandled {
|
||||||
|
@ -257,21 +260,25 @@ impl From<ErrorHandled> for InterpErrorInfo<'_> {
|
||||||
|
|
||||||
impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
|
impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
|
||||||
fn from(kind: InterpError<'tcx>) -> Self {
|
fn from(kind: InterpError<'tcx>) -> Self {
|
||||||
let backtrace = match env::var("RUSTC_CTFE_BACKTRACE") {
|
let capture_backtrace = tls::with_context_opt(|ctxt| {
|
||||||
// Matching `RUST_BACKTRACE` -- we treat "0" the same as "not present".
|
if let Some(ctxt) = ctxt {
|
||||||
Ok(ref val) if val != "0" => {
|
*Lock::borrow(&ctxt.tcx.sess.ctfe_backtrace)
|
||||||
let mut backtrace = Backtrace::new_unresolved();
|
} else {
|
||||||
|
CtfeBacktrace::Disabled
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if val == "immediate" {
|
let backtrace = match capture_backtrace {
|
||||||
|
CtfeBacktrace::Disabled => None,
|
||||||
|
CtfeBacktrace::Capture => Some(Box::new(Backtrace::new_unresolved())),
|
||||||
|
CtfeBacktrace::Immediate => {
|
||||||
// Print it now.
|
// Print it now.
|
||||||
|
let mut backtrace = Backtrace::new_unresolved();
|
||||||
print_backtrace(&mut backtrace);
|
print_backtrace(&mut backtrace);
|
||||||
None
|
None
|
||||||
} else {
|
|
||||||
Some(Box::new(backtrace))
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
InterpErrorInfo { kind, backtrace }
|
InterpErrorInfo { kind, backtrace }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -535,6 +535,16 @@ impl Token {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is the token an interpolated block (`$b:block`)?
|
||||||
|
pub fn is_whole_block(&self) -> bool {
|
||||||
|
if let Interpolated(ref nt) = self.kind {
|
||||||
|
if let NtBlock(..) = **nt {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` if the token is either the `mut` or `const` keyword.
|
/// Returns `true` if the token is either the `mut` or `const` keyword.
|
||||||
pub fn is_mutability(&self) -> bool {
|
pub fn is_mutability(&self) -> bool {
|
||||||
self.is_keyword(kw::Mut) || self.is_keyword(kw::Const)
|
self.is_keyword(kw::Mut) || self.is_keyword(kw::Const)
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use std::ffi::CString;
|
|
||||||
|
|
||||||
use crate::attributes;
|
use crate::attributes;
|
||||||
use libc::c_uint;
|
use libc::c_uint;
|
||||||
use rustc::bug;
|
use rustc::bug;
|
||||||
|
@ -50,8 +48,8 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut ModuleLlvm, kind: Alloc
|
||||||
args.len() as c_uint,
|
args.len() as c_uint,
|
||||||
False,
|
False,
|
||||||
);
|
);
|
||||||
let name = CString::new(format!("__rust_{}", method.name)).unwrap();
|
let name = format!("__rust_{}", method.name);
|
||||||
let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr(), ty);
|
let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
|
||||||
|
|
||||||
if tcx.sess.target.target.options.default_hidden_visibility {
|
if tcx.sess.target.target.options.default_hidden_visibility {
|
||||||
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
|
llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
|
||||||
|
@ -60,8 +58,9 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut ModuleLlvm, kind: Alloc
|
||||||
attributes::emit_uwtable(llfn, true);
|
attributes::emit_uwtable(llfn, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
let callee = CString::new(kind.fn_name(method.name)).unwrap();
|
let callee = kind.fn_name(method.name);
|
||||||
let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr(), ty);
|
let callee =
|
||||||
|
llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
|
||||||
llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
|
llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
|
||||||
|
|
||||||
let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
|
let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
|
||||||
|
@ -73,14 +72,8 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut ModuleLlvm, kind: Alloc
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
|
.map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let ret = llvm::LLVMRustBuildCall(
|
let ret =
|
||||||
llbuilder,
|
llvm::LLVMRustBuildCall(llbuilder, callee, args.as_ptr(), args.len() as c_uint, None);
|
||||||
callee,
|
|
||||||
args.as_ptr(),
|
|
||||||
args.len() as c_uint,
|
|
||||||
None,
|
|
||||||
"\0".as_ptr().cast(),
|
|
||||||
);
|
|
||||||
llvm::LLVMSetTailCall(ret, True);
|
llvm::LLVMSetTailCall(ret, True);
|
||||||
if output.is_some() {
|
if output.is_some() {
|
||||||
llvm::LLVMBuildRet(llbuilder, ret);
|
llvm::LLVMBuildRet(llbuilder, ret);
|
||||||
|
|
|
@ -12,7 +12,6 @@ use rustc_span::Span;
|
||||||
|
|
||||||
use libc::{c_char, c_uint};
|
use libc::{c_char, c_uint};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use std::ffi::{CStr, CString};
|
|
||||||
|
|
||||||
impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
||||||
fn codegen_inline_asm(
|
fn codegen_inline_asm(
|
||||||
|
@ -80,12 +79,11 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
||||||
_ => self.type_struct(&output_types, false),
|
_ => self.type_struct(&output_types, false),
|
||||||
};
|
};
|
||||||
|
|
||||||
let asm = CString::new(ia.asm.as_str().as_bytes()).unwrap();
|
let asm = ia.asm.as_str();
|
||||||
let constraint_cstr = CString::new(all_constraints).unwrap();
|
|
||||||
let r = inline_asm_call(
|
let r = inline_asm_call(
|
||||||
self,
|
self,
|
||||||
&asm,
|
&asm,
|
||||||
&constraint_cstr,
|
&all_constraints,
|
||||||
&inputs,
|
&inputs,
|
||||||
output_type,
|
output_type,
|
||||||
ia.volatile,
|
ia.volatile,
|
||||||
|
@ -125,17 +123,17 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
|
||||||
|
|
||||||
impl AsmMethods for CodegenCx<'ll, 'tcx> {
|
impl AsmMethods for CodegenCx<'ll, 'tcx> {
|
||||||
fn codegen_global_asm(&self, ga: &hir::GlobalAsm) {
|
fn codegen_global_asm(&self, ga: &hir::GlobalAsm) {
|
||||||
let asm = CString::new(ga.asm.as_str().as_bytes()).unwrap();
|
let asm = ga.asm.as_str();
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm::LLVMRustAppendModuleInlineAsm(self.llmod, asm.as_ptr());
|
llvm::LLVMRustAppendModuleInlineAsm(self.llmod, asm.as_ptr().cast(), asm.len());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inline_asm_call(
|
fn inline_asm_call(
|
||||||
bx: &mut Builder<'a, 'll, 'tcx>,
|
bx: &mut Builder<'a, 'll, 'tcx>,
|
||||||
asm: &CStr,
|
asm: &str,
|
||||||
cons: &CStr,
|
cons: &str,
|
||||||
inputs: &[&'ll Value],
|
inputs: &[&'ll Value],
|
||||||
output: &'ll llvm::Type,
|
output: &'ll llvm::Type,
|
||||||
volatile: bool,
|
volatile: bool,
|
||||||
|
@ -157,13 +155,15 @@ fn inline_asm_call(
|
||||||
let fty = bx.cx.type_func(&argtys[..], output);
|
let fty = bx.cx.type_func(&argtys[..], output);
|
||||||
unsafe {
|
unsafe {
|
||||||
// Ask LLVM to verify that the constraints are well-formed.
|
// Ask LLVM to verify that the constraints are well-formed.
|
||||||
let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr());
|
let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr().cast(), cons.len());
|
||||||
debug!("constraint verification result: {:?}", constraints_ok);
|
debug!("constraint verification result: {:?}", constraints_ok);
|
||||||
if constraints_ok {
|
if constraints_ok {
|
||||||
let v = llvm::LLVMRustInlineAsm(
|
let v = llvm::LLVMRustInlineAsm(
|
||||||
fty,
|
fty,
|
||||||
asm.as_ptr(),
|
asm.as_ptr().cast(),
|
||||||
cons.as_ptr(),
|
asm.len(),
|
||||||
|
cons.as_ptr().cast(),
|
||||||
|
cons.len(),
|
||||||
volatile,
|
volatile,
|
||||||
alignstack,
|
alignstack,
|
||||||
llvm::AsmDialect::from_generic(dia),
|
llvm::AsmDialect::from_generic(dia),
|
||||||
|
|
|
@ -1016,7 +1016,6 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
||||||
args.as_ptr() as *const &llvm::Value,
|
args.as_ptr() as *const &llvm::Value,
|
||||||
args.len() as c_uint,
|
args.len() as c_uint,
|
||||||
bundle,
|
bundle,
|
||||||
UNNAMED,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ use crate::value::Value;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use rustc::ty::Ty;
|
use rustc::ty::Ty;
|
||||||
use rustc_codegen_ssa::traits::*;
|
use rustc_codegen_ssa::traits::*;
|
||||||
use rustc_data_structures::small_c_str::SmallCStr;
|
|
||||||
|
|
||||||
/// Declare a function.
|
/// Declare a function.
|
||||||
///
|
///
|
||||||
|
@ -34,8 +33,9 @@ fn declare_raw_fn(
|
||||||
ty: &'ll Type,
|
ty: &'ll Type,
|
||||||
) -> &'ll Value {
|
) -> &'ll Value {
|
||||||
debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
|
debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
|
||||||
let namebuf = SmallCStr::new(name);
|
let llfn = unsafe {
|
||||||
let llfn = unsafe { llvm::LLVMRustGetOrInsertFunction(cx.llmod, namebuf.as_ptr(), ty) };
|
llvm::LLVMRustGetOrInsertFunction(cx.llmod, name.as_ptr().cast(), name.len(), ty)
|
||||||
|
};
|
||||||
|
|
||||||
llvm::SetFunctionCallConv(llfn, callconv);
|
llvm::SetFunctionCallConv(llfn, callconv);
|
||||||
// Function addresses in Rust are never significant, allowing functions to
|
// Function addresses in Rust are never significant, allowing functions to
|
||||||
|
@ -83,8 +83,7 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
||||||
|
|
||||||
fn get_declared_value(&self, name: &str) -> Option<&'ll Value> {
|
fn get_declared_value(&self, name: &str) -> Option<&'ll Value> {
|
||||||
debug!("get_declared_value(name={:?})", name);
|
debug!("get_declared_value(name={:?})", name);
|
||||||
let namebuf = SmallCStr::new(name);
|
unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_ptr().cast(), name.len()) }
|
||||||
unsafe { llvm::LLVMRustGetNamedValue(self.llmod, namebuf.as_ptr()) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_defined_value(&self, name: &str) -> Option<&'ll Value> {
|
fn get_defined_value(&self, name: &str) -> Option<&'ll Value> {
|
||||||
|
|
|
@ -732,7 +732,7 @@ extern "C" {
|
||||||
|
|
||||||
/// See Module::setModuleInlineAsm.
|
/// See Module::setModuleInlineAsm.
|
||||||
pub fn LLVMSetModuleInlineAsm(M: &Module, Asm: *const c_char);
|
pub fn LLVMSetModuleInlineAsm(M: &Module, Asm: *const c_char);
|
||||||
pub fn LLVMRustAppendModuleInlineAsm(M: &Module, Asm: *const c_char);
|
pub fn LLVMRustAppendModuleInlineAsm(M: &Module, Asm: *const c_char, AsmLen: size_t);
|
||||||
|
|
||||||
/// See llvm::LLVMTypeKind::getTypeID.
|
/// See llvm::LLVMTypeKind::getTypeID.
|
||||||
pub fn LLVMRustGetTypeKind(Ty: &Type) -> TypeKind;
|
pub fn LLVMRustGetTypeKind(Ty: &Type) -> TypeKind;
|
||||||
|
@ -879,13 +879,18 @@ extern "C" {
|
||||||
pub fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode);
|
pub fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode);
|
||||||
pub fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
|
pub fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
|
||||||
pub fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool);
|
pub fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool);
|
||||||
pub fn LLVMRustGetNamedValue(M: &Module, Name: *const c_char) -> Option<&Value>;
|
pub fn LLVMRustGetNamedValue(
|
||||||
|
M: &Module,
|
||||||
|
Name: *const c_char,
|
||||||
|
NameLen: size_t,
|
||||||
|
) -> Option<&Value>;
|
||||||
pub fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool);
|
pub fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool);
|
||||||
|
|
||||||
// Operations on functions
|
// Operations on functions
|
||||||
pub fn LLVMRustGetOrInsertFunction(
|
pub fn LLVMRustGetOrInsertFunction(
|
||||||
M: &'a Module,
|
M: &'a Module,
|
||||||
Name: *const c_char,
|
Name: *const c_char,
|
||||||
|
NameLen: size_t,
|
||||||
FunctionTy: &'a Type,
|
FunctionTy: &'a Type,
|
||||||
) -> &'a Value;
|
) -> &'a Value;
|
||||||
pub fn LLVMSetFunctionCallConv(Fn: &Value, CC: c_uint);
|
pub fn LLVMSetFunctionCallConv(Fn: &Value, CC: c_uint);
|
||||||
|
@ -1332,7 +1337,6 @@ extern "C" {
|
||||||
Args: *const &'a Value,
|
Args: *const &'a Value,
|
||||||
NumArgs: c_uint,
|
NumArgs: c_uint,
|
||||||
Bundle: Option<&OperandBundleDef<'a>>,
|
Bundle: Option<&OperandBundleDef<'a>>,
|
||||||
Name: *const c_char,
|
|
||||||
) -> &'a Value;
|
) -> &'a Value;
|
||||||
pub fn LLVMRustBuildMemCpy(
|
pub fn LLVMRustBuildMemCpy(
|
||||||
B: &Builder<'a>,
|
B: &Builder<'a>,
|
||||||
|
@ -1581,12 +1585,18 @@ extern "C" {
|
||||||
pub fn LLVMRustInlineAsm(
|
pub fn LLVMRustInlineAsm(
|
||||||
Ty: &Type,
|
Ty: &Type,
|
||||||
AsmString: *const c_char,
|
AsmString: *const c_char,
|
||||||
|
AsmStringLen: size_t,
|
||||||
Constraints: *const c_char,
|
Constraints: *const c_char,
|
||||||
|
ConstraintsLen: size_t,
|
||||||
SideEffects: Bool,
|
SideEffects: Bool,
|
||||||
AlignStack: Bool,
|
AlignStack: Bool,
|
||||||
Dialect: AsmDialect,
|
Dialect: AsmDialect,
|
||||||
) -> &Value;
|
) -> &Value;
|
||||||
pub fn LLVMRustInlineAsmVerify(Ty: &Type, Constraints: *const c_char) -> bool;
|
pub fn LLVMRustInlineAsmVerify(
|
||||||
|
Ty: &Type,
|
||||||
|
Constraints: *const c_char,
|
||||||
|
ConstraintsLen: size_t,
|
||||||
|
) -> bool;
|
||||||
|
|
||||||
pub fn LLVMRustDebugMetadataVersion() -> u32;
|
pub fn LLVMRustDebugMetadataVersion() -> u32;
|
||||||
pub fn LLVMRustVersionMajor() -> u32;
|
pub fn LLVMRustVersionMajor() -> u32;
|
||||||
|
|
|
@ -415,11 +415,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
AssertKind::BoundsCheck { ref len, ref index } => {
|
AssertKind::BoundsCheck { ref len, ref index } => {
|
||||||
let len = self.codegen_operand(&mut bx, len).immediate();
|
let len = self.codegen_operand(&mut bx, len).immediate();
|
||||||
let index = self.codegen_operand(&mut bx, index).immediate();
|
let index = self.codegen_operand(&mut bx, index).immediate();
|
||||||
(lang_items::PanicBoundsCheckFnLangItem, vec![location, index, len])
|
// It's `fn panic_bounds_check(index: usize, len: usize)`,
|
||||||
|
// and `#[track_caller]` adds an implicit third argument.
|
||||||
|
(lang_items::PanicBoundsCheckFnLangItem, vec![index, len, location])
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let msg_str = Symbol::intern(msg.description());
|
let msg_str = Symbol::intern(msg.description());
|
||||||
let msg = bx.const_str(msg_str);
|
let msg = bx.const_str(msg_str);
|
||||||
|
// It's `pub fn panic(expr: &str)`, with the wide reference being passed
|
||||||
|
// as two arguments, and `#[track_caller]` adds an implicit third argument.
|
||||||
(lang_items::PanicFnLangItem, vec![msg.0, msg.1, location])
|
(lang_items::PanicFnLangItem, vec![msg.0, msg.1, location])
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -411,6 +411,7 @@ E0735: include_str!("./error_codes/E0735.md"),
|
||||||
E0736: include_str!("./error_codes/E0736.md"),
|
E0736: include_str!("./error_codes/E0736.md"),
|
||||||
E0737: include_str!("./error_codes/E0737.md"),
|
E0737: include_str!("./error_codes/E0737.md"),
|
||||||
E0738: include_str!("./error_codes/E0738.md"),
|
E0738: include_str!("./error_codes/E0738.md"),
|
||||||
|
E0739: include_str!("./error_codes/E0739.md"),
|
||||||
E0740: include_str!("./error_codes/E0740.md"),
|
E0740: include_str!("./error_codes/E0740.md"),
|
||||||
E0741: include_str!("./error_codes/E0741.md"),
|
E0741: include_str!("./error_codes/E0741.md"),
|
||||||
E0742: include_str!("./error_codes/E0742.md"),
|
E0742: include_str!("./error_codes/E0742.md"),
|
||||||
|
@ -610,5 +611,4 @@ E0748: include_str!("./error_codes/E0748.md"),
|
||||||
E0722, // Malformed `#[optimize]` attribute
|
E0722, // Malformed `#[optimize]` attribute
|
||||||
E0724, // `#[ffi_returns_twice]` is only allowed in foreign functions
|
E0724, // `#[ffi_returns_twice]` is only allowed in foreign functions
|
||||||
E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
|
E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
|
||||||
E0739, // invalid track_caller application/syntax
|
|
||||||
}
|
}
|
||||||
|
|
13
src/librustc_error_codes/error_codes/E0739.md
Normal file
13
src/librustc_error_codes/error_codes/E0739.md
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
`#[track_caller]` can not be applied on struct.
|
||||||
|
|
||||||
|
Erroneous code example:
|
||||||
|
|
||||||
|
```compile_fail,E0739
|
||||||
|
#![feature(track_caller)]
|
||||||
|
#[track_caller]
|
||||||
|
struct Bar {
|
||||||
|
a: u8,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
[RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md
|
|
@ -280,7 +280,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||||
|
|
||||||
fn assert_panic(
|
fn assert_panic(
|
||||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
_span: Span,
|
|
||||||
msg: &AssertMessage<'tcx>,
|
msg: &AssertMessage<'tcx>,
|
||||||
_unwind: Option<mir::BasicBlock>,
|
_unwind: Option<mir::BasicBlock>,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
|
|
|
@ -165,7 +165,6 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||||
/// Called to evaluate `Assert` MIR terminators that trigger a panic.
|
/// Called to evaluate `Assert` MIR terminators that trigger a panic.
|
||||||
fn assert_panic(
|
fn assert_panic(
|
||||||
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
span: Span,
|
|
||||||
msg: &mir::AssertMessage<'tcx>,
|
msg: &mir::AssertMessage<'tcx>,
|
||||||
unwind: Option<mir::BasicBlock>,
|
unwind: Option<mir::BasicBlock>,
|
||||||
) -> InterpResult<'tcx>;
|
) -> InterpResult<'tcx>;
|
||||||
|
|
|
@ -95,7 +95,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
if expected == cond_val {
|
if expected == cond_val {
|
||||||
self.go_to_block(target);
|
self.go_to_block(target);
|
||||||
} else {
|
} else {
|
||||||
M::assert_panic(self, terminator.source_info.span, msg, cleanup)?;
|
M::assert_panic(self, msg, cleanup)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -197,7 +197,6 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
|
||||||
|
|
||||||
fn assert_panic(
|
fn assert_panic(
|
||||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
_span: Span,
|
|
||||||
_msg: &rustc::mir::AssertMessage<'tcx>,
|
_msg: &rustc::mir::AssertMessage<'tcx>,
|
||||||
_unwind: Option<rustc::mir::BasicBlock>,
|
_unwind: Option<rustc::mir::BasicBlock>,
|
||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#![feature(bool_to_option)]
|
#![feature(bool_to_option)]
|
||||||
#![feature(crate_visibility_modifier)]
|
#![feature(crate_visibility_modifier)]
|
||||||
|
#![feature(bindings_after_at)]
|
||||||
|
|
||||||
use rustc_ast::ast;
|
use rustc_ast::ast;
|
||||||
use rustc_ast::token::{self, Nonterminal};
|
use rustc_ast::token::{self, Nonterminal};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{Parser, PathStyle, TokenType};
|
use super::{Parser, PathStyle};
|
||||||
use rustc_ast::ast;
|
use rustc_ast::ast;
|
||||||
use rustc_ast::attr;
|
use rustc_ast::attr;
|
||||||
use rustc_ast::token::{self, Nonterminal};
|
use rustc_ast::token::{self, Nonterminal};
|
||||||
|
@ -10,14 +10,20 @@ use rustc_span::{Span, Symbol};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum InnerAttributeParsePolicy<'a> {
|
pub(super) enum InnerAttrPolicy<'a> {
|
||||||
Permitted,
|
Permitted,
|
||||||
NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
|
Forbidden { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
|
const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
|
||||||
permitted in this context";
|
permitted in this context";
|
||||||
|
|
||||||
|
pub(super) const DEFAULT_INNER_ATTR_FORBIDDEN: InnerAttrPolicy<'_> = InnerAttrPolicy::Forbidden {
|
||||||
|
reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
|
||||||
|
saw_doc_comment: false,
|
||||||
|
prev_attr_sp: None,
|
||||||
|
};
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a> Parser<'a> {
|
||||||
/// Parses attributes that appear before an item.
|
/// Parses attributes that appear before an item.
|
||||||
pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
|
pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
|
||||||
|
@ -25,8 +31,7 @@ impl<'a> Parser<'a> {
|
||||||
let mut just_parsed_doc_comment = false;
|
let mut just_parsed_doc_comment = false;
|
||||||
loop {
|
loop {
|
||||||
debug!("parse_outer_attributes: self.token={:?}", self.token);
|
debug!("parse_outer_attributes: self.token={:?}", self.token);
|
||||||
match self.token.kind {
|
if self.check(&token::Pound) {
|
||||||
token::Pound => {
|
|
||||||
let inner_error_reason = if just_parsed_doc_comment {
|
let inner_error_reason = if just_parsed_doc_comment {
|
||||||
"an inner attribute is not permitted following an outer doc comment"
|
"an inner attribute is not permitted following an outer doc comment"
|
||||||
} else if !attrs.is_empty() {
|
} else if !attrs.is_empty() {
|
||||||
|
@ -34,7 +39,7 @@ impl<'a> Parser<'a> {
|
||||||
} else {
|
} else {
|
||||||
DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
|
DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
|
||||||
};
|
};
|
||||||
let inner_parse_policy = InnerAttributeParsePolicy::NotPermitted {
|
let inner_parse_policy = InnerAttrPolicy::Forbidden {
|
||||||
reason: inner_error_reason,
|
reason: inner_error_reason,
|
||||||
saw_doc_comment: just_parsed_doc_comment,
|
saw_doc_comment: just_parsed_doc_comment,
|
||||||
prev_attr_sp: attrs.last().map(|a| a.span),
|
prev_attr_sp: attrs.last().map(|a| a.span),
|
||||||
|
@ -42,31 +47,28 @@ impl<'a> Parser<'a> {
|
||||||
let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?;
|
let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?;
|
||||||
attrs.push(attr);
|
attrs.push(attr);
|
||||||
just_parsed_doc_comment = false;
|
just_parsed_doc_comment = false;
|
||||||
}
|
} else if let token::DocComment(s) = self.token.kind {
|
||||||
token::DocComment(s) => {
|
|
||||||
let attr = self.mk_doc_comment(s);
|
let attr = self.mk_doc_comment(s);
|
||||||
if attr.style != ast::AttrStyle::Outer {
|
if attr.style != ast::AttrStyle::Outer {
|
||||||
let span = self.token.span;
|
self.struct_span_err(self.token.span, "expected outer doc comment")
|
||||||
let mut err = self.struct_span_err(span, "expected outer doc comment");
|
.note(
|
||||||
err.note(
|
|
||||||
"inner doc comments like this (starting with \
|
"inner doc comments like this (starting with \
|
||||||
`//!` or `/*!`) can only appear before items",
|
`//!` or `/*!`) can only appear before items",
|
||||||
);
|
)
|
||||||
return Err(err);
|
.emit();
|
||||||
}
|
}
|
||||||
attrs.push(attr);
|
attrs.push(attr);
|
||||||
self.bump();
|
self.bump();
|
||||||
just_parsed_doc_comment = true;
|
just_parsed_doc_comment = true;
|
||||||
}
|
} else {
|
||||||
_ => break,
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(attrs)
|
Ok(attrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute {
|
fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute {
|
||||||
let style = comments::doc_comment_style(&s.as_str());
|
attr::mk_doc_comment(comments::doc_comment_style(&s.as_str()), s, self.token.span)
|
||||||
attr::mk_doc_comment(style, s, self.token.span)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Matches `attribute = # ! [ meta_item ]`.
|
/// Matches `attribute = # ! [ meta_item ]`.
|
||||||
|
@ -75,96 +77,67 @@ impl<'a> Parser<'a> {
|
||||||
/// attribute.
|
/// attribute.
|
||||||
pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> {
|
pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> {
|
||||||
debug!("parse_attribute: permit_inner={:?} self.token={:?}", permit_inner, self.token);
|
debug!("parse_attribute: permit_inner={:?} self.token={:?}", permit_inner, self.token);
|
||||||
let inner_parse_policy = if permit_inner {
|
let inner_parse_policy =
|
||||||
InnerAttributeParsePolicy::Permitted
|
if permit_inner { InnerAttrPolicy::Permitted } else { DEFAULT_INNER_ATTR_FORBIDDEN };
|
||||||
} else {
|
|
||||||
InnerAttributeParsePolicy::NotPermitted {
|
|
||||||
reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
|
|
||||||
saw_doc_comment: false,
|
|
||||||
prev_attr_sp: None,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
|
self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy`
|
/// The same as `parse_attribute`, except it takes in an `InnerAttrPolicy`
|
||||||
/// that prescribes how to handle inner attributes.
|
/// that prescribes how to handle inner attributes.
|
||||||
fn parse_attribute_with_inner_parse_policy(
|
fn parse_attribute_with_inner_parse_policy(
|
||||||
&mut self,
|
&mut self,
|
||||||
inner_parse_policy: InnerAttributeParsePolicy<'_>,
|
inner_parse_policy: InnerAttrPolicy<'_>,
|
||||||
) -> PResult<'a, ast::Attribute> {
|
) -> PResult<'a, ast::Attribute> {
|
||||||
debug!(
|
debug!(
|
||||||
"parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
|
"parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
|
||||||
inner_parse_policy, self.token
|
inner_parse_policy, self.token
|
||||||
);
|
);
|
||||||
let (span, item, style) = match self.token.kind {
|
|
||||||
token::Pound => {
|
|
||||||
let lo = self.token.span;
|
let lo = self.token.span;
|
||||||
self.bump();
|
let (span, item, style) = if self.eat(&token::Pound) {
|
||||||
|
let style =
|
||||||
if let InnerAttributeParsePolicy::Permitted = inner_parse_policy {
|
if self.eat(&token::Not) { ast::AttrStyle::Inner } else { ast::AttrStyle::Outer };
|
||||||
self.expected_tokens.push(TokenType::Token(token::Not));
|
|
||||||
}
|
|
||||||
|
|
||||||
let style = if self.token == token::Not {
|
|
||||||
self.bump();
|
|
||||||
ast::AttrStyle::Inner
|
|
||||||
} else {
|
|
||||||
ast::AttrStyle::Outer
|
|
||||||
};
|
|
||||||
|
|
||||||
self.expect(&token::OpenDelim(token::Bracket))?;
|
self.expect(&token::OpenDelim(token::Bracket))?;
|
||||||
let item = self.parse_attr_item()?;
|
let item = self.parse_attr_item()?;
|
||||||
self.expect(&token::CloseDelim(token::Bracket))?;
|
self.expect(&token::CloseDelim(token::Bracket))?;
|
||||||
let hi = self.prev_token.span;
|
let attr_sp = lo.to(self.prev_token.span);
|
||||||
|
|
||||||
let attr_sp = lo.to(hi);
|
// Emit error if inner attribute is encountered and forbidden.
|
||||||
|
|
||||||
// Emit error if inner attribute is encountered and not permitted
|
|
||||||
if style == ast::AttrStyle::Inner {
|
if style == ast::AttrStyle::Inner {
|
||||||
if let InnerAttributeParsePolicy::NotPermitted {
|
self.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy);
|
||||||
reason,
|
|
||||||
saw_doc_comment,
|
|
||||||
prev_attr_sp,
|
|
||||||
} = inner_parse_policy
|
|
||||||
{
|
|
||||||
let prev_attr_note = if saw_doc_comment {
|
|
||||||
"previous doc comment"
|
|
||||||
} else {
|
|
||||||
"previous outer attribute"
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut diagnostic = self.struct_span_err(attr_sp, reason);
|
|
||||||
|
|
||||||
if let Some(prev_attr_sp) = prev_attr_sp {
|
|
||||||
diagnostic
|
|
||||||
.span_label(attr_sp, "not permitted following an outer attribute")
|
|
||||||
.span_label(prev_attr_sp, prev_attr_note);
|
|
||||||
}
|
|
||||||
|
|
||||||
diagnostic
|
|
||||||
.note(
|
|
||||||
"inner attributes, like `#![no_std]`, annotate the item \
|
|
||||||
enclosing them, and are usually found at the beginning of \
|
|
||||||
source files. Outer attributes, like `#[test]`, annotate the \
|
|
||||||
item following them.",
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(attr_sp, item, style)
|
(attr_sp, item, style)
|
||||||
}
|
} else {
|
||||||
_ => {
|
|
||||||
let token_str = pprust::token_to_string(&self.token);
|
let token_str = pprust::token_to_string(&self.token);
|
||||||
let msg = &format!("expected `#`, found `{}`", token_str);
|
let msg = &format!("expected `#`, found `{}`", token_str);
|
||||||
return Err(self.struct_span_err(self.token.span, msg));
|
return Err(self.struct_span_err(self.token.span, msg));
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(attr::mk_attr_from_item(style, item, span))
|
Ok(attr::mk_attr_from_item(style, item, span))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy<'_>) {
|
||||||
|
if let InnerAttrPolicy::Forbidden { reason, saw_doc_comment, prev_attr_sp } = policy {
|
||||||
|
let prev_attr_note =
|
||||||
|
if saw_doc_comment { "previous doc comment" } else { "previous outer attribute" };
|
||||||
|
|
||||||
|
let mut diag = self.struct_span_err(attr_sp, reason);
|
||||||
|
|
||||||
|
if let Some(prev_attr_sp) = prev_attr_sp {
|
||||||
|
diag.span_label(attr_sp, "not permitted following an outer attribute")
|
||||||
|
.span_label(prev_attr_sp, prev_attr_note);
|
||||||
|
}
|
||||||
|
|
||||||
|
diag.note(
|
||||||
|
"inner attributes, like `#![no_std]`, annotate the item enclosing them, \
|
||||||
|
and are usually found at the beginning of source files. \
|
||||||
|
Outer attributes, like `#[test]`, annotate the item following them.",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses an inner part of an attribute (the path and following tokens).
|
/// Parses an inner part of an attribute (the path and following tokens).
|
||||||
/// The tokens must be either a delimited token stream, or empty token stream,
|
/// The tokens must be either a delimited token stream, or empty token stream,
|
||||||
/// or the "legacy" key-value form.
|
/// or the "legacy" key-value form.
|
||||||
|
@ -200,18 +173,12 @@ impl<'a> Parser<'a> {
|
||||||
crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
|
crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
|
||||||
let mut attrs: Vec<ast::Attribute> = vec![];
|
let mut attrs: Vec<ast::Attribute> = vec![];
|
||||||
loop {
|
loop {
|
||||||
match self.token.kind {
|
// Only try to parse if it is an inner attribute (has `!`).
|
||||||
token::Pound => {
|
if self.check(&token::Pound) && self.look_ahead(1, |t| t == &token::Not) {
|
||||||
// Don't even try to parse if it's not an inner attribute.
|
|
||||||
if !self.look_ahead(1, |t| t == &token::Not) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let attr = self.parse_attribute(true)?;
|
let attr = self.parse_attribute(true)?;
|
||||||
assert_eq!(attr.style, ast::AttrStyle::Inner);
|
assert_eq!(attr.style, ast::AttrStyle::Inner);
|
||||||
attrs.push(attr);
|
attrs.push(attr);
|
||||||
}
|
} else if let token::DocComment(s) = self.token.kind {
|
||||||
token::DocComment(s) => {
|
|
||||||
// We need to get the position of this token before we bump.
|
// We need to get the position of this token before we bump.
|
||||||
let attr = self.mk_doc_comment(s);
|
let attr = self.mk_doc_comment(s);
|
||||||
if attr.style == ast::AttrStyle::Inner {
|
if attr.style == ast::AttrStyle::Inner {
|
||||||
|
@ -220,8 +187,8 @@ impl<'a> Parser<'a> {
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
_ => break,
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(attrs)
|
Ok(attrs)
|
||||||
|
@ -232,12 +199,10 @@ impl<'a> Parser<'a> {
|
||||||
debug!("checking if {:?} is unusuffixed", lit);
|
debug!("checking if {:?} is unusuffixed", lit);
|
||||||
|
|
||||||
if !lit.kind.is_unsuffixed() {
|
if !lit.kind.is_unsuffixed() {
|
||||||
let msg = "suffixed literals are not allowed in attributes";
|
self.struct_span_err(lit.span, "suffixed literals are not allowed in attributes")
|
||||||
self.struct_span_err(lit.span, msg)
|
|
||||||
.help(
|
.help(
|
||||||
"instead of using a suffixed literal \
|
"instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), \
|
||||||
(`1u8`, `1.0f32`, etc.), use an unsuffixed version \
|
use an unsuffixed version (`1`, `1.0`, etc.)",
|
||||||
(`1`, `1.0`, etc.)",
|
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -673,10 +673,28 @@ impl<'a> Parser<'a> {
|
||||||
/// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`.
|
/// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`.
|
||||||
fn parse_borrow_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
|
fn parse_borrow_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
|
||||||
self.expect_and()?;
|
self.expect_and()?;
|
||||||
|
let has_lifetime = self.token.is_lifetime() && self.look_ahead(1, |t| t != &token::Colon);
|
||||||
|
let lifetime = has_lifetime.then(|| self.expect_lifetime()); // For recovery, see below.
|
||||||
let (borrow_kind, mutbl) = self.parse_borrow_modifiers(lo);
|
let (borrow_kind, mutbl) = self.parse_borrow_modifiers(lo);
|
||||||
let expr = self.parse_prefix_expr(None);
|
let expr = self.parse_prefix_expr(None);
|
||||||
let (span, expr) = self.interpolated_or_expr_span(expr)?;
|
let (hi, expr) = self.interpolated_or_expr_span(expr)?;
|
||||||
Ok((lo.to(span), ExprKind::AddrOf(borrow_kind, mutbl, expr)))
|
let span = lo.to(hi);
|
||||||
|
if let Some(lt) = lifetime {
|
||||||
|
self.error_remove_borrow_lifetime(span, lt.ident.span);
|
||||||
|
}
|
||||||
|
Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {
|
||||||
|
self.struct_span_err(span, "borrow expressions cannot be annotated with lifetimes")
|
||||||
|
.span_label(lt_span, "annotated with lifetime here")
|
||||||
|
.span_suggestion(
|
||||||
|
lt_span,
|
||||||
|
"remove the lifetime annotation",
|
||||||
|
String::new(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse `mut?` or `raw [ const | mut ]`.
|
/// Parse `mut?` or `raw [ const | mut ]`.
|
||||||
|
@ -901,7 +919,7 @@ impl<'a> Parser<'a> {
|
||||||
} else if self.eat_lt() {
|
} else if self.eat_lt() {
|
||||||
let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
|
let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
|
||||||
Ok(self.mk_expr(lo.to(path.span), ExprKind::Path(Some(qself), path), attrs))
|
Ok(self.mk_expr(lo.to(path.span), ExprKind::Path(Some(qself), path), attrs))
|
||||||
} else if self.token.is_path_start() {
|
} else if self.check_path() {
|
||||||
self.parse_path_start_expr(attrs)
|
self.parse_path_start_expr(attrs)
|
||||||
} else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) {
|
} else if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) {
|
||||||
self.parse_closure_expr(attrs)
|
self.parse_closure_expr(attrs)
|
||||||
|
@ -1067,26 +1085,44 @@ impl<'a> Parser<'a> {
|
||||||
self.maybe_recover_from_bad_qpath(expr, true)
|
self.maybe_recover_from_bad_qpath(expr, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse `'label: $expr`. The label is already parsed.
|
||||||
fn parse_labeled_expr(&mut self, label: Label, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
fn parse_labeled_expr(&mut self, label: Label, attrs: AttrVec) -> PResult<'a, P<Expr>> {
|
||||||
let lo = label.ident.span;
|
let lo = label.ident.span;
|
||||||
self.expect(&token::Colon)?;
|
let label = Some(label);
|
||||||
if self.eat_keyword(kw::While) {
|
let ate_colon = self.eat(&token::Colon);
|
||||||
return self.parse_while_expr(Some(label), lo, attrs);
|
let expr = if self.eat_keyword(kw::While) {
|
||||||
}
|
self.parse_while_expr(label, lo, attrs)
|
||||||
if self.eat_keyword(kw::For) {
|
} else if self.eat_keyword(kw::For) {
|
||||||
return self.parse_for_expr(Some(label), lo, attrs);
|
self.parse_for_expr(label, lo, attrs)
|
||||||
}
|
} else if self.eat_keyword(kw::Loop) {
|
||||||
if self.eat_keyword(kw::Loop) {
|
self.parse_loop_expr(label, lo, attrs)
|
||||||
return self.parse_loop_expr(Some(label), lo, attrs);
|
} else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
|
||||||
}
|
self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs)
|
||||||
if self.token == token::OpenDelim(token::Brace) {
|
} else {
|
||||||
return self.parse_block_expr(Some(label), lo, BlockCheckMode::Default, attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
let msg = "expected `while`, `for`, `loop` or `{` after a label";
|
let msg = "expected `while`, `for`, `loop` or `{` after a label";
|
||||||
self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit();
|
self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit();
|
||||||
// Continue as an expression in an effort to recover on `'label: non_block_expr`.
|
// Continue as an expression in an effort to recover on `'label: non_block_expr`.
|
||||||
self.parse_expr()
|
self.parse_expr()
|
||||||
|
}?;
|
||||||
|
|
||||||
|
if !ate_colon {
|
||||||
|
self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error_labeled_expr_must_be_followed_by_colon(&self, lo: Span, span: Span) {
|
||||||
|
self.struct_span_err(span, "labeled expression must be followed by `:`")
|
||||||
|
.span_label(lo, "the label")
|
||||||
|
.span_suggestion_short(
|
||||||
|
lo.shrink_to_hi(),
|
||||||
|
"add `:` after the label",
|
||||||
|
": ".to_string(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
.note("labels are used before loops and blocks, allowing e.g., `break 'label` to them")
|
||||||
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
|
/// Recover on the syntax `do catch { ... }` suggesting `try { ... }` instead.
|
||||||
|
@ -1363,18 +1399,20 @@ impl<'a> Parser<'a> {
|
||||||
opt_label: Option<Label>,
|
opt_label: Option<Label>,
|
||||||
lo: Span,
|
lo: Span,
|
||||||
blk_mode: BlockCheckMode,
|
blk_mode: BlockCheckMode,
|
||||||
outer_attrs: AttrVec,
|
mut attrs: AttrVec,
|
||||||
) -> PResult<'a, P<Expr>> {
|
) -> PResult<'a, P<Expr>> {
|
||||||
if let Some(label) = opt_label {
|
if let Some(label) = opt_label {
|
||||||
self.sess.gated_spans.gate(sym::label_break_value, label.ident.span);
|
self.sess.gated_spans.gate(sym::label_break_value, label.ident.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.expect(&token::OpenDelim(token::Brace))?;
|
if self.token.is_whole_block() {
|
||||||
|
self.struct_span_err(self.token.span, "cannot use a `block` macro fragment here")
|
||||||
|
.span_label(lo.to(self.token.span), "the `block` fragment is within this context")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
|
||||||
let mut attrs = outer_attrs;
|
let (inner_attrs, blk) = self.parse_block_common(lo, blk_mode)?;
|
||||||
attrs.extend(self.parse_inner_attributes()?);
|
attrs.extend(inner_attrs);
|
||||||
|
|
||||||
let blk = self.parse_block_tail(lo, blk_mode)?;
|
|
||||||
Ok(self.mk_expr(blk.span, ExprKind::Block(blk, opt_label), attrs))
|
Ok(self.mk_expr(blk.span, ExprKind::Block(blk, opt_label), attrs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1476,13 +1514,16 @@ impl<'a> Parser<'a> {
|
||||||
let thn = if self.eat_keyword(kw::Else) || !cond.returns() {
|
let thn = if self.eat_keyword(kw::Else) || !cond.returns() {
|
||||||
self.error_missing_if_cond(lo, cond.span)
|
self.error_missing_if_cond(lo, cond.span)
|
||||||
} else {
|
} else {
|
||||||
|
let attrs = self.parse_outer_attributes()?; // For recovery.
|
||||||
let not_block = self.token != token::OpenDelim(token::Brace);
|
let not_block = self.token != token::OpenDelim(token::Brace);
|
||||||
self.parse_block().map_err(|mut err| {
|
let block = self.parse_block().map_err(|mut err| {
|
||||||
if not_block {
|
if not_block {
|
||||||
err.span_label(lo, "this `if` expression has a condition, but no block");
|
err.span_label(lo, "this `if` expression has a condition, but no block");
|
||||||
}
|
}
|
||||||
err
|
err
|
||||||
})?
|
})?;
|
||||||
|
self.error_on_if_block_attrs(lo, false, block.span, &attrs);
|
||||||
|
block
|
||||||
};
|
};
|
||||||
let els = if self.eat_keyword(kw::Else) { Some(self.parse_else_expr()?) } else { None };
|
let els = if self.eat_keyword(kw::Else) { Some(self.parse_else_expr()?) } else { None };
|
||||||
Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els), attrs))
|
Ok(self.mk_expr(lo.to(self.prev_token.span), ExprKind::If(cond, thn, els), attrs))
|
||||||
|
@ -1524,12 +1565,40 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
/// Parses an `else { ... }` expression (`else` token already eaten).
|
/// Parses an `else { ... }` expression (`else` token already eaten).
|
||||||
fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
|
fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
|
||||||
if self.eat_keyword(kw::If) {
|
let ctx_span = self.prev_token.span; // `else`
|
||||||
self.parse_if_expr(AttrVec::new())
|
let attrs = self.parse_outer_attributes()?; // For recovery.
|
||||||
|
let expr = if self.eat_keyword(kw::If) {
|
||||||
|
self.parse_if_expr(AttrVec::new())?
|
||||||
} else {
|
} else {
|
||||||
let blk = self.parse_block()?;
|
let blk = self.parse_block()?;
|
||||||
Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()))
|
self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new())
|
||||||
|
};
|
||||||
|
self.error_on_if_block_attrs(ctx_span, true, expr.span, &attrs);
|
||||||
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn error_on_if_block_attrs(
|
||||||
|
&self,
|
||||||
|
ctx_span: Span,
|
||||||
|
is_ctx_else: bool,
|
||||||
|
branch_span: Span,
|
||||||
|
attrs: &[ast::Attribute],
|
||||||
|
) {
|
||||||
|
let (span, last) = match attrs {
|
||||||
|
[] => return,
|
||||||
|
[x0 @ xn] | [x0, .., xn] => (x0.span.to(xn.span), xn.span),
|
||||||
|
};
|
||||||
|
let ctx = if is_ctx_else { "else" } else { "if" };
|
||||||
|
self.struct_span_err(last, "outer attributes are not allowed on `if` and `else` branches")
|
||||||
|
.span_label(branch_span, "the attributes are attached to this branch")
|
||||||
|
.span_label(ctx_span, format!("the branch belongs to this `{}`", ctx))
|
||||||
|
.span_suggestion(
|
||||||
|
span,
|
||||||
|
"remove the attributes",
|
||||||
|
String::new(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
|
/// Parses `for <src_pat> in <src_expr> <src_loop_block>` (`for` token already eaten).
|
||||||
|
|
|
@ -218,7 +218,7 @@ impl<'a> Parser<'a> {
|
||||||
} else if vis.node.is_pub() && self.isnt_macro_invocation() {
|
} else if vis.node.is_pub() && self.isnt_macro_invocation() {
|
||||||
self.recover_missing_kw_before_item()?;
|
self.recover_missing_kw_before_item()?;
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
} else if macros_allowed && self.token.is_path_start() {
|
} else if macros_allowed && self.check_path() {
|
||||||
// MACRO INVOCATION ITEM
|
// MACRO INVOCATION ITEM
|
||||||
(Ident::invalid(), ItemKind::Mac(self.parse_item_macro(vis)?))
|
(Ident::invalid(), ItemKind::Mac(self.parse_item_macro(vis)?))
|
||||||
} else {
|
} else {
|
||||||
|
@ -352,8 +352,7 @@ impl<'a> Parser<'a> {
|
||||||
fn recover_attrs_no_item(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> {
|
fn recover_attrs_no_item(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> {
|
||||||
let (start, end) = match attrs {
|
let (start, end) = match attrs {
|
||||||
[] => return Ok(()),
|
[] => return Ok(()),
|
||||||
[x0] => (x0, x0),
|
[x0 @ xn] | [x0, .., xn] => (x0, xn),
|
||||||
[x0, .., xn] => (x0, xn),
|
|
||||||
};
|
};
|
||||||
let msg = if end.is_doc_comment() {
|
let msg = if end.is_doc_comment() {
|
||||||
"expected item after doc comment"
|
"expected item after doc comment"
|
||||||
|
@ -1411,23 +1410,28 @@ impl<'a> Parser<'a> {
|
||||||
/// This can either be `;` when there's no body,
|
/// This can either be `;` when there's no body,
|
||||||
/// or e.g. a block when the function is a provided one.
|
/// or e.g. a block when the function is a provided one.
|
||||||
fn parse_fn_body(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, Option<P<Block>>> {
|
fn parse_fn_body(&mut self, attrs: &mut Vec<Attribute>) -> PResult<'a, Option<P<Block>>> {
|
||||||
let (inner_attrs, body) = match self.token.kind {
|
let (inner_attrs, body) = if self.check(&token::Semi) {
|
||||||
token::Semi => {
|
self.bump(); // `;`
|
||||||
self.bump();
|
|
||||||
(Vec::new(), None)
|
(Vec::new(), None)
|
||||||
}
|
} else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
|
||||||
token::OpenDelim(token::Brace) => {
|
self.parse_inner_attrs_and_block().map(|(attrs, body)| (attrs, Some(body)))?
|
||||||
let (attrs, body) = self.parse_inner_attrs_and_block()?;
|
} else if self.token.kind == token::Eq {
|
||||||
(attrs, Some(body))
|
// Recover `fn foo() = $expr;`.
|
||||||
}
|
self.bump(); // `=`
|
||||||
token::Interpolated(ref nt) => match **nt {
|
let eq_sp = self.prev_token.span;
|
||||||
token::NtBlock(..) => {
|
let _ = self.parse_expr()?;
|
||||||
let (attrs, body) = self.parse_inner_attrs_and_block()?;
|
self.expect_semi()?; // `;`
|
||||||
(attrs, Some(body))
|
let span = eq_sp.to(self.prev_token.span);
|
||||||
}
|
self.struct_span_err(span, "function body cannot be `= expression;`")
|
||||||
_ => return self.expected_semi_or_open_brace(),
|
.multipart_suggestion(
|
||||||
},
|
"surround the expression with `{` and `}` instead of `=` and `;`",
|
||||||
_ => return self.expected_semi_or_open_brace(),
|
vec![(eq_sp, "{".to_string()), (self.prev_token.span, " }".to_string())],
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
(Vec::new(), Some(self.mk_block_err(span)))
|
||||||
|
} else {
|
||||||
|
return self.expected_semi_or_open_brace();
|
||||||
};
|
};
|
||||||
attrs.extend(inner_attrs);
|
attrs.extend(inner_attrs);
|
||||||
Ok(body)
|
Ok(body)
|
||||||
|
|
|
@ -704,7 +704,7 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> {
|
fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> {
|
||||||
if self.token.is_path_start() {
|
if self.check_path() {
|
||||||
let lo = self.token.span;
|
let lo = self.token.span;
|
||||||
let (qself, path) = if self.eat_lt() {
|
let (qself, path) = if self.eat_lt() {
|
||||||
// Parse a qualified path
|
// Parse a qualified path
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN;
|
||||||
use super::diagnostics::Error;
|
use super::diagnostics::Error;
|
||||||
use super::expr::LhsExpr;
|
use super::expr::LhsExpr;
|
||||||
use super::pat::GateOr;
|
use super::pat::GateOr;
|
||||||
|
@ -47,10 +48,7 @@ impl<'a> Parser<'a> {
|
||||||
self.bump(); // `var`
|
self.bump(); // `var`
|
||||||
let msg = "write `let` instead of `var` to introduce a new variable";
|
let msg = "write `let` instead of `var` to introduce a new variable";
|
||||||
self.recover_stmt_local(lo, attrs.into(), msg, "let")?
|
self.recover_stmt_local(lo, attrs.into(), msg, "let")?
|
||||||
} else if self.token.is_path_start()
|
} else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
|
||||||
&& !self.token.is_qpath_start()
|
|
||||||
&& !self.is_path_start_item()
|
|
||||||
{
|
|
||||||
// We have avoided contextual keywords like `union`, items with `crate` visibility,
|
// We have avoided contextual keywords like `union`, items with `crate` visibility,
|
||||||
// or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
|
// or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
|
||||||
// that starts like a path (1 token), but it fact not a path.
|
// that starts like a path (1 token), but it fact not a path.
|
||||||
|
@ -238,15 +236,11 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
/// Parses a block. No inner attributes are allowed.
|
/// Parses a block. No inner attributes are allowed.
|
||||||
pub fn parse_block(&mut self) -> PResult<'a, P<Block>> {
|
pub fn parse_block(&mut self) -> PResult<'a, P<Block>> {
|
||||||
maybe_whole!(self, NtBlock, |x| x);
|
let (attrs, block) = self.parse_inner_attrs_and_block()?;
|
||||||
|
if let [.., last] = &*attrs {
|
||||||
let lo = self.token.span;
|
self.error_on_forbidden_inner_attr(last.span, DEFAULT_INNER_ATTR_FORBIDDEN);
|
||||||
|
|
||||||
if !self.eat(&token::OpenDelim(token::Brace)) {
|
|
||||||
return self.error_block_no_opening_brace();
|
|
||||||
}
|
}
|
||||||
|
Ok(block)
|
||||||
self.parse_block_tail(lo, BlockCheckMode::Default)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
|
fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> {
|
||||||
|
@ -262,16 +256,14 @@ impl<'a> Parser<'a> {
|
||||||
//
|
//
|
||||||
// which is valid in other languages, but not Rust.
|
// which is valid in other languages, but not Rust.
|
||||||
match self.parse_stmt_without_recovery() {
|
match self.parse_stmt_without_recovery() {
|
||||||
Ok(Some(stmt)) => {
|
|
||||||
if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace))
|
|
||||||
|| do_not_suggest_help
|
|
||||||
{
|
|
||||||
// If the next token is an open brace (e.g., `if a b {`), the place-
|
// If the next token is an open brace (e.g., `if a b {`), the place-
|
||||||
// inside-a-block suggestion would be more likely wrong than right.
|
// inside-a-block suggestion would be more likely wrong than right.
|
||||||
e.span_label(sp, "expected `{`");
|
Ok(Some(_))
|
||||||
return Err(e);
|
if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace))
|
||||||
}
|
|| do_not_suggest_help => {}
|
||||||
let stmt_span = if self.eat(&token::Semi) {
|
Ok(Some(stmt)) => {
|
||||||
|
let stmt_own_line = self.sess.source_map().is_line_before_span_empty(sp);
|
||||||
|
let stmt_span = if stmt_own_line && self.eat(&token::Semi) {
|
||||||
// Expand the span to include the semicolon.
|
// Expand the span to include the semicolon.
|
||||||
stmt.span.with_hi(self.prev_token.span.hi())
|
stmt.span.with_hi(self.prev_token.span.hi())
|
||||||
} else {
|
} else {
|
||||||
|
@ -300,21 +292,28 @@ impl<'a> Parser<'a> {
|
||||||
/// Parses a block. Inner attributes are allowed.
|
/// Parses a block. Inner attributes are allowed.
|
||||||
pub(super) fn parse_inner_attrs_and_block(
|
pub(super) fn parse_inner_attrs_and_block(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
) -> PResult<'a, (Vec<Attribute>, P<Block>)> {
|
||||||
|
self.parse_block_common(self.token.span, BlockCheckMode::Default)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a block. Inner attributes are allowed.
|
||||||
|
pub(super) fn parse_block_common(
|
||||||
|
&mut self,
|
||||||
|
lo: Span,
|
||||||
|
blk_mode: BlockCheckMode,
|
||||||
) -> PResult<'a, (Vec<Attribute>, P<Block>)> {
|
) -> PResult<'a, (Vec<Attribute>, P<Block>)> {
|
||||||
maybe_whole!(self, NtBlock, |x| (Vec::new(), x));
|
maybe_whole!(self, NtBlock, |x| (Vec::new(), x));
|
||||||
|
|
||||||
let lo = self.token.span;
|
if !self.eat(&token::OpenDelim(token::Brace)) {
|
||||||
self.expect(&token::OpenDelim(token::Brace))?;
|
return self.error_block_no_opening_brace();
|
||||||
Ok((self.parse_inner_attributes()?, self.parse_block_tail(lo, BlockCheckMode::Default)?))
|
}
|
||||||
|
|
||||||
|
Ok((self.parse_inner_attributes()?, self.parse_block_tail(lo, blk_mode)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses the rest of a block expression or function body.
|
/// Parses the rest of a block expression or function body.
|
||||||
/// Precondition: already parsed the '{'.
|
/// Precondition: already parsed the '{'.
|
||||||
pub(super) fn parse_block_tail(
|
fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P<Block>> {
|
||||||
&mut self,
|
|
||||||
lo: Span,
|
|
||||||
s: BlockCheckMode,
|
|
||||||
) -> PResult<'a, P<Block>> {
|
|
||||||
let mut stmts = vec![];
|
let mut stmts = vec![];
|
||||||
while !self.eat(&token::CloseDelim(token::Brace)) {
|
while !self.eat(&token::CloseDelim(token::Brace)) {
|
||||||
if self.token == token::Eof {
|
if self.token == token::Eof {
|
||||||
|
|
|
@ -142,24 +142,20 @@ impl<'a> Parser<'a> {
|
||||||
} else {
|
} else {
|
||||||
let path = self.parse_path(PathStyle::Type)?;
|
let path = self.parse_path(PathStyle::Type)?;
|
||||||
let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
|
let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
|
||||||
self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)?
|
self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?
|
||||||
}
|
}
|
||||||
} else if self.eat_keyword(kw::Impl) {
|
} else if self.eat_keyword(kw::Impl) {
|
||||||
self.parse_impl_ty(&mut impl_dyn_multi)?
|
self.parse_impl_ty(&mut impl_dyn_multi)?
|
||||||
} else if self.is_explicit_dyn_type() {
|
} else if self.is_explicit_dyn_type() {
|
||||||
self.parse_dyn_ty(&mut impl_dyn_multi)?
|
self.parse_dyn_ty(&mut impl_dyn_multi)?
|
||||||
} else if self.check(&token::Question)
|
|
||||||
|| self.check_lifetime() && self.look_ahead(1, |t| t.is_like_plus())
|
|
||||||
{
|
|
||||||
// Bound list (trait object type)
|
|
||||||
let bounds = self.parse_generic_bounds_common(allow_plus, None)?;
|
|
||||||
TyKind::TraitObject(bounds, TraitObjectSyntax::None)
|
|
||||||
} else if self.eat_lt() {
|
} else if self.eat_lt() {
|
||||||
// Qualified path
|
// Qualified path
|
||||||
let (qself, path) = self.parse_qpath(PathStyle::Type)?;
|
let (qself, path) = self.parse_qpath(PathStyle::Type)?;
|
||||||
TyKind::Path(Some(qself), path)
|
TyKind::Path(Some(qself), path)
|
||||||
} else if self.token.is_path_start() {
|
} else if self.check_path() {
|
||||||
self.parse_path_start_ty(lo, allow_plus)?
|
self.parse_path_start_ty(lo, allow_plus)?
|
||||||
|
} else if self.can_begin_bound() {
|
||||||
|
self.parse_bare_trait_object(lo, allow_plus)?
|
||||||
} else if self.eat(&token::DotDotDot) {
|
} else if self.eat(&token::DotDotDot) {
|
||||||
if allow_c_variadic == AllowCVariadic::Yes {
|
if allow_c_variadic == AllowCVariadic::Yes {
|
||||||
TyKind::CVarArgs
|
TyKind::CVarArgs
|
||||||
|
@ -203,21 +199,12 @@ impl<'a> Parser<'a> {
|
||||||
match ty.kind {
|
match ty.kind {
|
||||||
// `(TY_BOUND_NOPAREN) + BOUND + ...`.
|
// `(TY_BOUND_NOPAREN) + BOUND + ...`.
|
||||||
TyKind::Path(None, path) if maybe_bounds => {
|
TyKind::Path(None, path) if maybe_bounds => {
|
||||||
self.parse_remaining_bounds(Vec::new(), path, lo, true)
|
self.parse_remaining_bounds_path(Vec::new(), path, lo, true)
|
||||||
}
|
}
|
||||||
TyKind::TraitObject(mut bounds, TraitObjectSyntax::None)
|
TyKind::TraitObject(bounds, TraitObjectSyntax::None)
|
||||||
if maybe_bounds && bounds.len() == 1 && !trailing_plus =>
|
if maybe_bounds && bounds.len() == 1 && !trailing_plus =>
|
||||||
{
|
{
|
||||||
let path = match bounds.remove(0) {
|
self.parse_remaining_bounds(bounds, true)
|
||||||
GenericBound::Trait(pt, ..) => pt.trait_ref.path,
|
|
||||||
GenericBound::Outlives(..) => {
|
|
||||||
return Err(self.struct_span_err(
|
|
||||||
ty.span,
|
|
||||||
"expected trait bound, not lifetime bound",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.parse_remaining_bounds(Vec::new(), path, lo, true)
|
|
||||||
}
|
}
|
||||||
// `(TYPE)`
|
// `(TYPE)`
|
||||||
_ => Ok(TyKind::Paren(P(ty))),
|
_ => Ok(TyKind::Paren(P(ty))),
|
||||||
|
@ -227,18 +214,35 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_remaining_bounds(
|
fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
|
||||||
|
let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus());
|
||||||
|
let bounds = self.parse_generic_bounds_common(allow_plus, None)?;
|
||||||
|
if lt_no_plus {
|
||||||
|
self.struct_span_err(lo, "lifetime in trait object type must be followed by `+`").emit()
|
||||||
|
}
|
||||||
|
Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_remaining_bounds_path(
|
||||||
&mut self,
|
&mut self,
|
||||||
generic_params: Vec<GenericParam>,
|
generic_params: Vec<GenericParam>,
|
||||||
path: ast::Path,
|
path: ast::Path,
|
||||||
lo: Span,
|
lo: Span,
|
||||||
parse_plus: bool,
|
parse_plus: bool,
|
||||||
) -> PResult<'a, TyKind> {
|
) -> PResult<'a, TyKind> {
|
||||||
assert_ne!(self.token, token::Question);
|
|
||||||
|
|
||||||
let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_token.span));
|
let poly_trait_ref = PolyTraitRef::new(generic_params, path, lo.to(self.prev_token.span));
|
||||||
let mut bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)];
|
let bounds = vec![GenericBound::Trait(poly_trait_ref, TraitBoundModifier::None)];
|
||||||
if parse_plus {
|
self.parse_remaining_bounds(bounds, parse_plus)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse the remainder of a bare trait object type given an already parsed list.
|
||||||
|
fn parse_remaining_bounds(
|
||||||
|
&mut self,
|
||||||
|
mut bounds: GenericBounds,
|
||||||
|
plus: bool,
|
||||||
|
) -> PResult<'a, TyKind> {
|
||||||
|
assert_ne!(self.token, token::Question);
|
||||||
|
if plus {
|
||||||
self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
|
self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
|
||||||
bounds.append(&mut self.parse_generic_bounds(Some(self.prev_token.span))?);
|
bounds.append(&mut self.parse_generic_bounds(Some(self.prev_token.span))?);
|
||||||
}
|
}
|
||||||
|
@ -358,7 +362,7 @@ impl<'a> Parser<'a> {
|
||||||
}))
|
}))
|
||||||
} else if allow_plus == AllowPlus::Yes && self.check_plus() {
|
} else if allow_plus == AllowPlus::Yes && self.check_plus() {
|
||||||
// `Trait1 + Trait2 + 'a`
|
// `Trait1 + Trait2 + 'a`
|
||||||
self.parse_remaining_bounds(Vec::new(), path, lo, true)
|
self.parse_remaining_bounds_path(Vec::new(), path, lo, true)
|
||||||
} else {
|
} else {
|
||||||
// Just a type path.
|
// Just a type path.
|
||||||
Ok(TyKind::Path(None, path))
|
Ok(TyKind::Path(None, path))
|
||||||
|
|
|
@ -49,6 +49,18 @@ pub struct OptimizationFuel {
|
||||||
out_of_fuel: bool,
|
out_of_fuel: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The behavior of the CTFE engine when an error occurs with regards to backtraces.
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum CtfeBacktrace {
|
||||||
|
/// Do nothing special, return the error as usual without a backtrace.
|
||||||
|
Disabled,
|
||||||
|
/// Capture a backtrace at the point the error is created and return it in the error
|
||||||
|
/// (to be printed later if/when the error ever actually gets shown to the user).
|
||||||
|
Capture,
|
||||||
|
/// Capture a backtrace at the point the error is created and immediately print it out.
|
||||||
|
Immediate,
|
||||||
|
}
|
||||||
|
|
||||||
/// Represents the data associated with a compilation
|
/// Represents the data associated with a compilation
|
||||||
/// session for a single crate.
|
/// session for a single crate.
|
||||||
pub struct Session {
|
pub struct Session {
|
||||||
|
@ -139,6 +151,11 @@ pub struct Session {
|
||||||
/// Path for libraries that will take preference over libraries shipped by Rust.
|
/// Path for libraries that will take preference over libraries shipped by Rust.
|
||||||
/// Used by windows-gnu targets to priortize system mingw-w64 libraries.
|
/// Used by windows-gnu targets to priortize system mingw-w64 libraries.
|
||||||
pub system_library_path: OneThread<RefCell<Option<Option<PathBuf>>>>,
|
pub system_library_path: OneThread<RefCell<Option<Option<PathBuf>>>>,
|
||||||
|
|
||||||
|
/// Tracks the current behavior of the CTFE engine when an error occurs.
|
||||||
|
/// Options range from returning the error without a backtrace to returning an error
|
||||||
|
/// and immediately printing the backtrace to stderr.
|
||||||
|
pub ctfe_backtrace: Lock<CtfeBacktrace>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PerfStats {
|
pub struct PerfStats {
|
||||||
|
@ -1040,6 +1057,12 @@ fn build_session_(
|
||||||
sopts.debugging_opts.time_passes,
|
sopts.debugging_opts.time_passes,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let ctfe_backtrace = Lock::new(match env::var("RUSTC_CTFE_BACKTRACE") {
|
||||||
|
Ok(ref val) if val == "immediate" => CtfeBacktrace::Immediate,
|
||||||
|
Ok(ref val) if val != "0" => CtfeBacktrace::Capture,
|
||||||
|
_ => CtfeBacktrace::Disabled,
|
||||||
|
});
|
||||||
|
|
||||||
let sess = Session {
|
let sess = Session {
|
||||||
target: target_cfg,
|
target: target_cfg,
|
||||||
host,
|
host,
|
||||||
|
@ -1078,6 +1101,7 @@ fn build_session_(
|
||||||
trait_methods_not_found: Lock::new(Default::default()),
|
trait_methods_not_found: Lock::new(Default::default()),
|
||||||
confused_type_with_std_module: Lock::new(Default::default()),
|
confused_type_with_std_module: Lock::new(Default::default()),
|
||||||
system_library_path: OneThread::new(RefCell::new(Default::default())),
|
system_library_path: OneThread::new(RefCell::new(Default::default())),
|
||||||
|
ctfe_backtrace,
|
||||||
};
|
};
|
||||||
|
|
||||||
validate_commandline_args_with_session_available(&sess);
|
validate_commandline_args_with_session_available(&sess);
|
||||||
|
|
|
@ -517,6 +517,13 @@ impl SourceMap {
|
||||||
Ok((lo, hi))
|
Ok((lo, hi))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_line_before_span_empty(&self, sp: Span) -> bool {
|
||||||
|
match self.span_to_prev_source(sp) {
|
||||||
|
Ok(s) => s.split('\n').last().map(|l| l.trim_start().is_empty()).unwrap_or(false),
|
||||||
|
Err(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn span_to_lines(&self, sp: Span) -> FileLinesResult {
|
pub fn span_to_lines(&self, sp: Span) -> FileLinesResult {
|
||||||
debug!("span_to_lines(sp={:?})", sp);
|
debug!("span_to_lines(sp={:?})", sp);
|
||||||
let (lo, hi) = self.is_valid_span(sp)?;
|
let (lo, hi) = self.is_valid_span(sp)?;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -24,6 +25,33 @@ use crate::opts;
|
||||||
use crate::passes::{self, Condition, DefaultPassOption};
|
use crate::passes::{self, Condition, DefaultPassOption};
|
||||||
use crate::theme;
|
use crate::theme;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum OutputFormat {
|
||||||
|
Json,
|
||||||
|
Html,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OutputFormat {
|
||||||
|
pub fn is_json(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
OutputFormat::Json => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for OutputFormat {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
"json" => Ok(OutputFormat::Json),
|
||||||
|
"html" => Ok(OutputFormat::Html),
|
||||||
|
_ => Err(format!("unknown output format `{}`", value)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Configuration options for rustdoc.
|
/// Configuration options for rustdoc.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Options {
|
pub struct Options {
|
||||||
|
@ -115,6 +143,8 @@ pub struct Options {
|
||||||
pub crate_version: Option<String>,
|
pub crate_version: Option<String>,
|
||||||
/// Collected options specific to outputting final pages.
|
/// Collected options specific to outputting final pages.
|
||||||
pub render_options: RenderOptions,
|
pub render_options: RenderOptions,
|
||||||
|
/// Output format rendering (used only for "show-coverage" option for the moment)
|
||||||
|
pub output_format: Option<OutputFormat>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Options {
|
impl fmt::Debug for Options {
|
||||||
|
@ -425,14 +455,6 @@ impl Options {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match matches.opt_str("w").as_ref().map(|s| &**s) {
|
|
||||||
Some("html") | None => {}
|
|
||||||
Some(s) => {
|
|
||||||
diag.struct_err(&format!("unknown output format: {}", s)).emit();
|
|
||||||
return Err(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let index_page = matches.opt_str("index-page").map(|s| PathBuf::from(&s));
|
let index_page = matches.opt_str("index-page").map(|s| PathBuf::from(&s));
|
||||||
if let Some(ref index_page) = index_page {
|
if let Some(ref index_page) = index_page {
|
||||||
if !index_page.is_file() {
|
if !index_page.is_file() {
|
||||||
|
@ -469,6 +491,29 @@ impl Options {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let output_format = match matches.opt_str("output-format") {
|
||||||
|
Some(s) => match OutputFormat::try_from(s.as_str()) {
|
||||||
|
Ok(o) => {
|
||||||
|
if o.is_json() && !show_coverage {
|
||||||
|
diag.struct_err("json output format isn't supported for doc generation")
|
||||||
|
.emit();
|
||||||
|
return Err(1);
|
||||||
|
} else if !o.is_json() && show_coverage {
|
||||||
|
diag.struct_err(
|
||||||
|
"html output format isn't supported for the --show-coverage option",
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
return Err(1);
|
||||||
|
}
|
||||||
|
Some(o)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
diag.struct_err(&e).emit();
|
||||||
|
return Err(1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
let crate_name = matches.opt_str("crate-name");
|
let crate_name = matches.opt_str("crate-name");
|
||||||
let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro);
|
let proc_macro_crate = crate_types.contains(&CrateType::ProcMacro);
|
||||||
let playground_url = matches.opt_str("playground-url");
|
let playground_url = matches.opt_str("playground-url");
|
||||||
|
@ -553,6 +598,7 @@ impl Options {
|
||||||
generate_search_filter,
|
generate_search_filter,
|
||||||
generate_redirect_pages,
|
generate_redirect_pages,
|
||||||
},
|
},
|
||||||
|
output_format,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,6 +614,9 @@ fn check_deprecated_options(matches: &getopts::Matches, diag: &rustc_errors::Han
|
||||||
|
|
||||||
for flag in deprecated_flags.iter() {
|
for flag in deprecated_flags.iter() {
|
||||||
if matches.opt_present(flag) {
|
if matches.opt_present(flag) {
|
||||||
|
if *flag == "output-format" && matches.opt_present("show-coverage") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let mut err =
|
let mut err =
|
||||||
diag.struct_warn(&format!("the '{}' flag is considered deprecated", flag));
|
diag.struct_warn(&format!("the '{}' flag is considered deprecated", flag));
|
||||||
err.warn(
|
err.warn(
|
||||||
|
|
|
@ -228,6 +228,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
||||||
mut manual_passes,
|
mut manual_passes,
|
||||||
display_warnings,
|
display_warnings,
|
||||||
render_options,
|
render_options,
|
||||||
|
output_format,
|
||||||
..
|
..
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
|
@ -385,6 +386,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
||||||
|
|
||||||
let mut renderinfo = RenderInfo::default();
|
let mut renderinfo = RenderInfo::default();
|
||||||
renderinfo.access_levels = access_levels;
|
renderinfo.access_levels = access_levels;
|
||||||
|
renderinfo.output_format = output_format;
|
||||||
|
|
||||||
let mut ctxt = DocContext {
|
let mut ctxt = DocContext {
|
||||||
tcx,
|
tcx,
|
||||||
|
|
|
@ -60,7 +60,7 @@ use serde::ser::SerializeSeq;
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
|
|
||||||
use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy};
|
use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy};
|
||||||
use crate::config::RenderOptions;
|
use crate::config::{OutputFormat, RenderOptions};
|
||||||
use crate::docfs::{DocFS, ErrorStorage, PathError};
|
use crate::docfs::{DocFS, ErrorStorage, PathError};
|
||||||
use crate::doctree;
|
use crate::doctree;
|
||||||
use crate::html::escape::Escape;
|
use crate::html::escape::Escape;
|
||||||
|
@ -270,6 +270,7 @@ pub struct RenderInfo {
|
||||||
pub deref_trait_did: Option<DefId>,
|
pub deref_trait_did: Option<DefId>,
|
||||||
pub deref_mut_trait_did: Option<DefId>,
|
pub deref_mut_trait_did: Option<DefId>,
|
||||||
pub owned_box_did: Option<DefId>,
|
pub owned_box_did: Option<DefId>,
|
||||||
|
pub output_format: Option<OutputFormat>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper structs for rendering items/sidebars and carrying along contextual
|
// Helper structs for rendering items/sidebars and carrying along contextual
|
||||||
|
|
|
@ -139,6 +139,7 @@ impl Cache {
|
||||||
deref_trait_did,
|
deref_trait_did,
|
||||||
deref_mut_trait_did,
|
deref_mut_trait_did,
|
||||||
owned_box_did,
|
owned_box_did,
|
||||||
|
..
|
||||||
} = renderinfo;
|
} = renderinfo;
|
||||||
|
|
||||||
let external_paths =
|
let external_paths =
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::clean;
|
use crate::clean;
|
||||||
|
use crate::config::OutputFormat;
|
||||||
use crate::core::DocContext;
|
use crate::core::DocContext;
|
||||||
use crate::fold::{self, DocFolder};
|
use crate::fold::{self, DocFolder};
|
||||||
use crate::passes::Pass;
|
use crate::passes::Pass;
|
||||||
|
@ -6,6 +7,8 @@ use crate::passes::Pass;
|
||||||
use rustc_ast::attr;
|
use rustc_ast::attr;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::FileName;
|
use rustc_span::FileName;
|
||||||
|
use serde::Serialize;
|
||||||
|
use serde_json;
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::ops;
|
use std::ops;
|
||||||
|
@ -16,16 +19,16 @@ pub const CALCULATE_DOC_COVERAGE: Pass = Pass {
|
||||||
description: "counts the number of items with and without documentation",
|
description: "counts the number of items with and without documentation",
|
||||||
};
|
};
|
||||||
|
|
||||||
fn calculate_doc_coverage(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
|
fn calculate_doc_coverage(krate: clean::Crate, ctx: &DocContext<'_>) -> clean::Crate {
|
||||||
let mut calc = CoverageCalculator::default();
|
let mut calc = CoverageCalculator::new();
|
||||||
let krate = calc.fold_crate(krate);
|
let krate = calc.fold_crate(krate);
|
||||||
|
|
||||||
calc.print_results();
|
calc.print_results(ctx.renderinfo.borrow().output_format);
|
||||||
|
|
||||||
krate
|
krate
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Copy, Clone)]
|
#[derive(Default, Copy, Clone, Serialize)]
|
||||||
struct ItemCount {
|
struct ItemCount {
|
||||||
total: u64,
|
total: u64,
|
||||||
with_docs: u64,
|
with_docs: u64,
|
||||||
|
@ -64,13 +67,41 @@ impl ops::AddAssign for ItemCount {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct CoverageCalculator {
|
struct CoverageCalculator {
|
||||||
items: BTreeMap<FileName, ItemCount>,
|
items: BTreeMap<FileName, ItemCount>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn limit_filename_len(filename: String) -> String {
|
||||||
|
let nb_chars = filename.chars().count();
|
||||||
|
if nb_chars > 35 {
|
||||||
|
"...".to_string()
|
||||||
|
+ &filename[filename.char_indices().nth(nb_chars - 32).map(|x| x.0).unwrap_or(0)..]
|
||||||
|
} else {
|
||||||
|
filename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CoverageCalculator {
|
impl CoverageCalculator {
|
||||||
fn print_results(&self) {
|
fn new() -> CoverageCalculator {
|
||||||
|
CoverageCalculator { items: Default::default() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_json(&self) -> String {
|
||||||
|
serde_json::to_string(
|
||||||
|
&self
|
||||||
|
.items
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| (k.to_string(), v))
|
||||||
|
.collect::<BTreeMap<String, &ItemCount>>(),
|
||||||
|
)
|
||||||
|
.expect("failed to convert JSON data to string")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_results(&self, output_format: Option<OutputFormat>) {
|
||||||
|
if output_format.map(|o| o.is_json()).unwrap_or_else(|| false) {
|
||||||
|
println!("{}", self.to_json());
|
||||||
|
return;
|
||||||
|
}
|
||||||
let mut total = ItemCount::default();
|
let mut total = ItemCount::default();
|
||||||
|
|
||||||
fn print_table_line() {
|
fn print_table_line() {
|
||||||
|
@ -93,15 +124,7 @@ impl CoverageCalculator {
|
||||||
|
|
||||||
for (file, &count) in &self.items {
|
for (file, &count) in &self.items {
|
||||||
if let Some(percentage) = count.percentage() {
|
if let Some(percentage) = count.percentage() {
|
||||||
let mut name = file.to_string();
|
print_table_record(&limit_filename_len(file.to_string()), count, percentage);
|
||||||
// if a filename is too long, shorten it so we don't blow out the table
|
|
||||||
// FIXME(misdreavus): this needs to count graphemes, and probably also track
|
|
||||||
// double-wide characters...
|
|
||||||
if name.len() > 35 {
|
|
||||||
name = "...".to_string() + &name[name.len() - 32..];
|
|
||||||
}
|
|
||||||
|
|
||||||
print_table_record(&name, count, percentage);
|
|
||||||
|
|
||||||
total += count;
|
total += count;
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,16 +112,18 @@ extern "C" void LLVMRustPrintPassTimings() {
|
||||||
TimerGroup::printAll(OS);
|
TimerGroup::printAll(OS);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" LLVMValueRef LLVMRustGetNamedValue(LLVMModuleRef M,
|
extern "C" LLVMValueRef LLVMRustGetNamedValue(LLVMModuleRef M, const char *Name,
|
||||||
const char *Name) {
|
size_t NameLen) {
|
||||||
return wrap(unwrap(M)->getNamedValue(Name));
|
return wrap(unwrap(M)->getNamedValue(StringRef(Name, NameLen)));
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M,
|
extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M,
|
||||||
const char *Name,
|
const char *Name,
|
||||||
|
size_t NameLen,
|
||||||
LLVMTypeRef FunctionTy) {
|
LLVMTypeRef FunctionTy) {
|
||||||
return wrap(
|
return wrap(unwrap(M)
|
||||||
unwrap(M)->getOrInsertFunction(Name, unwrap<FunctionType>(FunctionTy))
|
->getOrInsertFunction(StringRef(Name, NameLen),
|
||||||
|
unwrap<FunctionType>(FunctionTy))
|
||||||
#if LLVM_VERSION_GE(9, 0)
|
#if LLVM_VERSION_GE(9, 0)
|
||||||
.getCallee()
|
.getCallee()
|
||||||
#endif
|
#endif
|
||||||
|
@ -395,22 +397,26 @@ static InlineAsm::AsmDialect fromRust(LLVMRustAsmDialect Dialect) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" LLVMValueRef LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString,
|
extern "C" LLVMValueRef
|
||||||
char *Constraints,
|
LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, size_t AsmStringLen,
|
||||||
LLVMBool HasSideEffects,
|
char *Constraints, size_t ConstraintsLen,
|
||||||
LLVMBool IsAlignStack,
|
LLVMBool HasSideEffects, LLVMBool IsAlignStack,
|
||||||
LLVMRustAsmDialect Dialect) {
|
LLVMRustAsmDialect Dialect) {
|
||||||
return wrap(InlineAsm::get(unwrap<FunctionType>(Ty), AsmString, Constraints,
|
return wrap(InlineAsm::get(unwrap<FunctionType>(Ty),
|
||||||
|
StringRef(AsmString, AsmStringLen),
|
||||||
|
StringRef(Constraints, ConstraintsLen),
|
||||||
HasSideEffects, IsAlignStack, fromRust(Dialect)));
|
HasSideEffects, IsAlignStack, fromRust(Dialect)));
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty,
|
extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints,
|
||||||
char *Constraints) {
|
size_t ConstraintsLen) {
|
||||||
return InlineAsm::Verify(unwrap<FunctionType>(Ty), Constraints);
|
return InlineAsm::Verify(unwrap<FunctionType>(Ty),
|
||||||
|
StringRef(Constraints, ConstraintsLen));
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void LLVMRustAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm) {
|
extern "C" void LLVMRustAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm,
|
||||||
unwrap(M)->appendModuleInlineAsm(StringRef(Asm));
|
size_t AsmLen) {
|
||||||
|
unwrap(M)->appendModuleInlineAsm(StringRef(Asm, AsmLen));
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef DIBuilder *LLVMRustDIBuilderRef;
|
typedef DIBuilder *LLVMRustDIBuilderRef;
|
||||||
|
@ -1282,12 +1288,11 @@ extern "C" void LLVMRustFreeOperandBundleDef(OperandBundleDef *Bundle) {
|
||||||
|
|
||||||
extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn,
|
extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMValueRef Fn,
|
||||||
LLVMValueRef *Args, unsigned NumArgs,
|
LLVMValueRef *Args, unsigned NumArgs,
|
||||||
OperandBundleDef *Bundle,
|
OperandBundleDef *Bundle) {
|
||||||
const char *Name) {
|
|
||||||
unsigned Len = Bundle ? 1 : 0;
|
unsigned Len = Bundle ? 1 : 0;
|
||||||
ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len);
|
ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, Len);
|
||||||
return wrap(unwrap(B)->CreateCall(
|
return wrap(unwrap(B)->CreateCall(
|
||||||
unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Bundles, Name));
|
unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Bundles));
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B,
|
extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B,
|
||||||
|
|
4
src/test/rustdoc-ui/coverage/html.rs
Normal file
4
src/test/rustdoc-ui/coverage/html.rs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
// compile-flags:-Z unstable-options --output-format html --show-coverage
|
||||||
|
|
||||||
|
/// Foo
|
||||||
|
pub struct Xo;
|
2
src/test/rustdoc-ui/coverage/html.stderr
Normal file
2
src/test/rustdoc-ui/coverage/html.stderr
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
error: html output format isn't supported for the --show-coverage option
|
||||||
|
|
27
src/test/rustdoc-ui/coverage/json.rs
Normal file
27
src/test/rustdoc-ui/coverage/json.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// build-pass
|
||||||
|
// compile-flags:-Z unstable-options --output-format json --show-coverage
|
||||||
|
|
||||||
|
pub mod foo {
|
||||||
|
/// Hello!
|
||||||
|
pub struct Foo;
|
||||||
|
/// Bar
|
||||||
|
pub enum Bar { A }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// X
|
||||||
|
pub struct X;
|
||||||
|
|
||||||
|
/// Bar
|
||||||
|
pub mod bar {
|
||||||
|
/// bar
|
||||||
|
pub struct Bar;
|
||||||
|
/// X
|
||||||
|
pub enum X { Y }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// yolo
|
||||||
|
pub enum Yolo { X }
|
||||||
|
|
||||||
|
pub struct Xo<T: Clone> {
|
||||||
|
x: T,
|
||||||
|
}
|
1
src/test/rustdoc-ui/coverage/json.stdout
Normal file
1
src/test/rustdoc-ui/coverage/json.stdout
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{"$DIR/json.rs":{"total":13,"with_docs":7}}
|
|
@ -32,11 +32,11 @@ LL | X() {}
|
||||||
LL | }
|
LL | }
|
||||||
| - the item list ends here
|
| - the item list ends here
|
||||||
|
|
||||||
error: expected `[`, found `#`
|
error: expected one of `!` or `[`, found `#`
|
||||||
--> $DIR/issue-40006.rs:19:17
|
--> $DIR/issue-40006.rs:19:17
|
||||||
|
|
|
|
||||||
LL | fn xxx() { ### }
|
LL | fn xxx() { ### }
|
||||||
| ^ expected `[`
|
| ^ expected one of `!` or `[`
|
||||||
|
|
||||||
error: expected one of `!` or `::`, found `=`
|
error: expected one of `!` or `::`, found `=`
|
||||||
--> $DIR/issue-40006.rs:22:7
|
--> $DIR/issue-40006.rs:22:7
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
trait Foo {
|
trait Foo {
|
||||||
type Bar<,>;
|
type Bar<,>;
|
||||||
//~^ ERROR expected one of `>`, `const`, identifier, or lifetime, found `,`
|
//~^ ERROR expected one of `#`, `>`, `const`, identifier, or lifetime, found `,`
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
error: expected one of `>`, `const`, identifier, or lifetime, found `,`
|
error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,`
|
||||||
--> $DIR/empty_generics.rs:5:14
|
--> $DIR/empty_generics.rs:5:14
|
||||||
|
|
|
|
||||||
LL | trait Foo {
|
LL | trait Foo {
|
||||||
| - while parsing this item list starting here
|
| - while parsing this item list starting here
|
||||||
LL | type Bar<,>;
|
LL | type Bar<,>;
|
||||||
| ^ expected one of `>`, `const`, identifier, or lifetime
|
| ^ expected one of `#`, `>`, `const`, identifier, or lifetime
|
||||||
LL |
|
LL |
|
||||||
LL | }
|
LL | }
|
||||||
| - the item list ends here
|
| - the item list ends here
|
||||||
|
|
|
@ -8,7 +8,7 @@ fn if_else_parse_error() {
|
||||||
#[cfg(FALSE)]
|
#[cfg(FALSE)]
|
||||||
fn else_attr_ifparse_error() {
|
fn else_attr_ifparse_error() {
|
||||||
if true {
|
if true {
|
||||||
} else #[attr] if false { //~ ERROR expected
|
} else #[attr] if false { //~ ERROR outer attributes are not allowed
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,18 +4,17 @@ error: expected expression, found keyword `else`
|
||||||
LL | } #[attr] else if false {
|
LL | } #[attr] else if false {
|
||||||
| ^^^^ expected expression
|
| ^^^^ expected expression
|
||||||
|
|
||||||
error: expected `{`, found `#`
|
error: outer attributes are not allowed on `if` and `else` branches
|
||||||
--> $DIR/else-attrs.rs:11:12
|
--> $DIR/else-attrs.rs:11:12
|
||||||
|
|
|
|
||||||
LL | } else #[attr] if false {
|
LL | } else #[attr] if false {
|
||||||
| ^ expected `{`
|
| _______----_^^^^^^^_-
|
||||||
|
|
| | | |
|
||||||
help: try placing this code inside a block
|
| | | help: remove the attributes
|
||||||
|
|
| | the branch belongs to this `else`
|
||||||
LL | } else #[attr] { if false {
|
LL | | } else {
|
||||||
LL | } else {
|
LL | | }
|
||||||
LL | } }
|
| |_____- the attributes are attached to this branch
|
||||||
|
|
|
||||||
|
|
||||||
error: expected expression, found keyword `else`
|
error: expected expression, found keyword `else`
|
||||||
--> $DIR/else-attrs.rs:20:15
|
--> $DIR/else-attrs.rs:20:15
|
||||||
|
|
|
@ -29,7 +29,7 @@ type Type_5_<'a> = Type_1_<'a, ()>;
|
||||||
|
|
||||||
|
|
||||||
type Type_8<'a,,> = &'a ();
|
type Type_8<'a,,> = &'a ();
|
||||||
//~^ error: expected one of `>`, `const`, identifier, or lifetime, found `,`
|
//~^ error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,`
|
||||||
|
|
||||||
|
|
||||||
//type Type_9<T,,> = Box<T>; // error: expected identifier, found `,`
|
//type Type_9<T,,> = Box<T>; // error: expected identifier, found `,`
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: expected one of `>`, `const`, identifier, or lifetime, found `,`
|
error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,`
|
||||||
--> $DIR/issue-20616-8.rs:31:16
|
--> $DIR/issue-20616-8.rs:31:16
|
||||||
|
|
|
|
||||||
LL | type Type_8<'a,,> = &'a ();
|
LL | type Type_8<'a,,> = &'a ();
|
||||||
| ^ expected one of `>`, `const`, identifier, or lifetime
|
| ^ expected one of `#`, `>`, `const`, identifier, or lifetime
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -32,4 +32,4 @@ type Type_5_<'a> = Type_1_<'a, ()>;
|
||||||
|
|
||||||
|
|
||||||
type Type_9<T,,> = Box<T>;
|
type Type_9<T,,> = Box<T>;
|
||||||
//~^ error: expected one of `>`, `const`, identifier, or lifetime, found `,`
|
//~^ error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,`
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: expected one of `>`, `const`, identifier, or lifetime, found `,`
|
error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,`
|
||||||
--> $DIR/issue-20616-9.rs:34:15
|
--> $DIR/issue-20616-9.rs:34:15
|
||||||
|
|
|
|
||||||
LL | type Type_9<T,,> = Box<T>;
|
LL | type Type_9<T,,> = Box<T>;
|
||||||
| ^ expected one of `>`, `const`, identifier, or lifetime
|
| ^ expected one of `#`, `>`, `const`, identifier, or lifetime
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -2,7 +2,10 @@ error: expected `{`, found `'b`
|
||||||
--> $DIR/label_break_value_illegal_uses.rs:6:12
|
--> $DIR/label_break_value_illegal_uses.rs:6:12
|
||||||
|
|
|
|
||||||
LL | unsafe 'b: {}
|
LL | unsafe 'b: {}
|
||||||
| ^^ expected `{`
|
| ^^----
|
||||||
|
| |
|
||||||
|
| expected `{`
|
||||||
|
| help: try placing this code inside a block: `{ 'b: {} }`
|
||||||
|
|
||||||
error: expected `{`, found `'b`
|
error: expected `{`, found `'b`
|
||||||
--> $DIR/label_break_value_illegal_uses.rs:10:13
|
--> $DIR/label_break_value_illegal_uses.rs:10:13
|
||||||
|
|
|
@ -39,35 +39,35 @@ fn main() {}
|
||||||
#[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; }
|
#[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; }
|
||||||
//~^ ERROR an inner attribute is not permitted in this context
|
//~^ ERROR an inner attribute is not permitted in this context
|
||||||
#[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
|
#[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
|
||||||
//~^ ERROR expected `{`, found `#`
|
//~^ ERROR outer attributes are not allowed on `if`
|
||||||
#[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; }
|
#[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; }
|
||||||
//~^ ERROR an inner attribute is not permitted in this context
|
//~^ ERROR an inner attribute is not permitted in this context
|
||||||
#[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; }
|
#[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; }
|
||||||
//~^ ERROR expected one of
|
//~^ ERROR expected one of
|
||||||
#[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; }
|
#[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; }
|
||||||
//~^ ERROR expected `{`, found `#`
|
//~^ ERROR outer attributes are not allowed on `if`
|
||||||
#[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; }
|
#[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; }
|
||||||
//~^ ERROR an inner attribute is not permitted in this context
|
//~^ ERROR an inner attribute is not permitted in this context
|
||||||
#[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
|
#[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
|
||||||
//~^ ERROR expected `{`, found `#`
|
//~^ ERROR outer attributes are not allowed on `if`
|
||||||
#[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
|
#[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
|
||||||
//~^ ERROR expected `{`, found `#`
|
//~^ ERROR outer attributes are not allowed on `if`
|
||||||
#[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; }
|
#[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; }
|
||||||
//~^ ERROR an inner attribute is not permitted in this context
|
//~^ ERROR an inner attribute is not permitted in this context
|
||||||
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
|
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
|
||||||
//~^ ERROR expected `{`, found `#`
|
//~^ ERROR outer attributes are not allowed on `if`
|
||||||
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; }
|
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; }
|
||||||
//~^ ERROR an inner attribute is not permitted in this context
|
//~^ ERROR an inner attribute is not permitted in this context
|
||||||
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; }
|
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; }
|
||||||
//~^ ERROR expected one of
|
//~^ ERROR expected one of
|
||||||
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
|
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
|
||||||
//~^ ERROR expected `{`, found `#`
|
//~^ ERROR outer attributes are not allowed on `if`
|
||||||
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; }
|
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; }
|
||||||
//~^ ERROR an inner attribute is not permitted in this context
|
//~^ ERROR an inner attribute is not permitted in this context
|
||||||
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
|
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
|
||||||
//~^ ERROR expected `{`, found `#`
|
//~^ ERROR outer attributes are not allowed on `if`
|
||||||
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
|
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
|
||||||
//~^ ERROR expected `{`, found `#`
|
//~^ ERROR outer attributes are not allowed on `if`
|
||||||
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; }
|
#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; }
|
||||||
//~^ ERROR an inner attribute is not permitted in this context
|
//~^ ERROR an inner attribute is not permitted in this context
|
||||||
|
|
||||||
|
|
|
@ -136,14 +136,14 @@ LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; }
|
||||||
|
|
|
|
||||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||||
|
|
||||||
error: expected `{`, found `#`
|
error: outer attributes are not allowed on `if` and `else` branches
|
||||||
--> $DIR/attr-stmt-expr-attr-bad.rs:41:37
|
--> $DIR/attr-stmt-expr-attr-bad.rs:41:37
|
||||||
|
|
|
|
||||||
LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
|
LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
|
||||||
| -- ^ --- help: try placing this code inside a block: `{ {}; }`
|
| -- ^^^^^^^ -- the attributes are attached to this branch
|
||||||
| | |
|
| | |
|
||||||
| | expected `{`
|
| | help: remove the attributes
|
||||||
| this `if` expression has a condition, but no block
|
| the branch belongs to this `if`
|
||||||
|
|
||||||
error: an inner attribute is not permitted in this context
|
error: an inner attribute is not permitted in this context
|
||||||
--> $DIR/attr-stmt-expr-attr-bad.rs:43:38
|
--> $DIR/attr-stmt-expr-attr-bad.rs:43:38
|
||||||
|
@ -159,13 +159,14 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#`
|
||||||
LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; }
|
LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; }
|
||||||
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
|
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
|
||||||
|
|
||||||
error: expected `{`, found `#`
|
error: outer attributes are not allowed on `if` and `else` branches
|
||||||
--> $DIR/attr-stmt-expr-attr-bad.rs:47:45
|
--> $DIR/attr-stmt-expr-attr-bad.rs:47:45
|
||||||
|
|
|
|
||||||
LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; }
|
LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; }
|
||||||
| ^ --- help: try placing this code inside a block: `{ {}; }`
|
| ---- ^^^^^^^ -- the attributes are attached to this branch
|
||||||
| |
|
| | |
|
||||||
| expected `{`
|
| | help: remove the attributes
|
||||||
|
| the branch belongs to this `else`
|
||||||
|
|
||||||
error: an inner attribute is not permitted in this context
|
error: an inner attribute is not permitted in this context
|
||||||
--> $DIR/attr-stmt-expr-attr-bad.rs:49:46
|
--> $DIR/attr-stmt-expr-attr-bad.rs:49:46
|
||||||
|
@ -175,22 +176,23 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; }
|
||||||
|
|
|
|
||||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||||
|
|
||||||
error: expected `{`, found `#`
|
error: outer attributes are not allowed on `if` and `else` branches
|
||||||
--> $DIR/attr-stmt-expr-attr-bad.rs:51:45
|
--> $DIR/attr-stmt-expr-attr-bad.rs:51:45
|
||||||
|
|
|
|
||||||
LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
|
LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
|
||||||
| ^ -------- help: try placing this code inside a block: `{ if 0 {}; }`
|
| ---- ^^^^^^^ ------- the attributes are attached to this branch
|
||||||
| |
|
| | |
|
||||||
| expected `{`
|
| | help: remove the attributes
|
||||||
|
| the branch belongs to this `else`
|
||||||
|
|
||||||
error: expected `{`, found `#`
|
error: outer attributes are not allowed on `if` and `else` branches
|
||||||
--> $DIR/attr-stmt-expr-attr-bad.rs:53:50
|
--> $DIR/attr-stmt-expr-attr-bad.rs:53:50
|
||||||
|
|
|
|
||||||
LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
|
LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
|
||||||
| -- ^ --- help: try placing this code inside a block: `{ {}; }`
|
| -- ^^^^^^^ -- the attributes are attached to this branch
|
||||||
| | |
|
| | |
|
||||||
| | expected `{`
|
| | help: remove the attributes
|
||||||
| this `if` expression has a condition, but no block
|
| the branch belongs to this `if`
|
||||||
|
|
||||||
error: an inner attribute is not permitted in this context
|
error: an inner attribute is not permitted in this context
|
||||||
--> $DIR/attr-stmt-expr-attr-bad.rs:55:51
|
--> $DIR/attr-stmt-expr-attr-bad.rs:55:51
|
||||||
|
@ -200,14 +202,14 @@ LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; }
|
||||||
|
|
|
|
||||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||||
|
|
||||||
error: expected `{`, found `#`
|
error: outer attributes are not allowed on `if` and `else` branches
|
||||||
--> $DIR/attr-stmt-expr-attr-bad.rs:57:45
|
--> $DIR/attr-stmt-expr-attr-bad.rs:57:45
|
||||||
|
|
|
|
||||||
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
|
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
|
||||||
| -- ^ --- help: try placing this code inside a block: `{ {}; }`
|
| -- ^^^^^^^ -- the attributes are attached to this branch
|
||||||
| | |
|
| | |
|
||||||
| | expected `{`
|
| | help: remove the attributes
|
||||||
| this `if` expression has a condition, but no block
|
| the branch belongs to this `if`
|
||||||
|
|
||||||
error: an inner attribute is not permitted in this context
|
error: an inner attribute is not permitted in this context
|
||||||
--> $DIR/attr-stmt-expr-attr-bad.rs:59:46
|
--> $DIR/attr-stmt-expr-attr-bad.rs:59:46
|
||||||
|
@ -223,13 +225,14 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#`
|
||||||
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; }
|
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; }
|
||||||
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
|
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
|
||||||
|
|
||||||
error: expected `{`, found `#`
|
error: outer attributes are not allowed on `if` and `else` branches
|
||||||
--> $DIR/attr-stmt-expr-attr-bad.rs:63:53
|
--> $DIR/attr-stmt-expr-attr-bad.rs:63:53
|
||||||
|
|
|
|
||||||
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
|
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
|
||||||
| ^ --- help: try placing this code inside a block: `{ {}; }`
|
| ---- ^^^^^^^ -- the attributes are attached to this branch
|
||||||
| |
|
| | |
|
||||||
| expected `{`
|
| | help: remove the attributes
|
||||||
|
| the branch belongs to this `else`
|
||||||
|
|
||||||
error: an inner attribute is not permitted in this context
|
error: an inner attribute is not permitted in this context
|
||||||
--> $DIR/attr-stmt-expr-attr-bad.rs:65:54
|
--> $DIR/attr-stmt-expr-attr-bad.rs:65:54
|
||||||
|
@ -239,22 +242,23 @@ LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; }
|
||||||
|
|
|
|
||||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
|
||||||
|
|
||||||
error: expected `{`, found `#`
|
error: outer attributes are not allowed on `if` and `else` branches
|
||||||
--> $DIR/attr-stmt-expr-attr-bad.rs:67:53
|
--> $DIR/attr-stmt-expr-attr-bad.rs:67:53
|
||||||
|
|
|
|
||||||
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
|
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
|
||||||
| ^ ---------------- help: try placing this code inside a block: `{ if let _ = 0 {}; }`
|
| ---- ^^^^^^^ --------------- the attributes are attached to this branch
|
||||||
| |
|
| | |
|
||||||
| expected `{`
|
| | help: remove the attributes
|
||||||
|
| the branch belongs to this `else`
|
||||||
|
|
||||||
error: expected `{`, found `#`
|
error: outer attributes are not allowed on `if` and `else` branches
|
||||||
--> $DIR/attr-stmt-expr-attr-bad.rs:69:66
|
--> $DIR/attr-stmt-expr-attr-bad.rs:69:66
|
||||||
|
|
|
|
||||||
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
|
LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
|
||||||
| -- ^ --- help: try placing this code inside a block: `{ {}; }`
|
| -- ^^^^^^^ -- the attributes are attached to this branch
|
||||||
| | |
|
| | |
|
||||||
| | expected `{`
|
| | help: remove the attributes
|
||||||
| this `if` expression has a condition, but no block
|
| the branch belongs to this `if`
|
||||||
|
|
||||||
error: an inner attribute is not permitted in this context
|
error: an inner attribute is not permitted in this context
|
||||||
--> $DIR/attr-stmt-expr-attr-bad.rs:71:67
|
--> $DIR/attr-stmt-expr-attr-bad.rs:71:67
|
||||||
|
|
15
src/test/ui/parser/bad-interpolated-block.rs
Normal file
15
src/test/ui/parser/bad-interpolated-block.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#![feature(label_break_value)]
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
macro_rules! m {
|
||||||
|
($b:block) => {
|
||||||
|
'lab: $b; //~ ERROR cannot use a `block` macro fragment here
|
||||||
|
unsafe $b; //~ ERROR cannot use a `block` macro fragment here
|
||||||
|
|x: u8| -> () $b; //~ ERROR cannot use a `block` macro fragment here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo() {
|
||||||
|
m!({});
|
||||||
|
}
|
39
src/test/ui/parser/bad-interpolated-block.stderr
Normal file
39
src/test/ui/parser/bad-interpolated-block.stderr
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
error: cannot use a `block` macro fragment here
|
||||||
|
--> $DIR/bad-interpolated-block.rs:7:15
|
||||||
|
|
|
||||||
|
LL | 'lab: $b;
|
||||||
|
| ------^^
|
||||||
|
| |
|
||||||
|
| the `block` fragment is within this context
|
||||||
|
...
|
||||||
|
LL | m!({});
|
||||||
|
| ------- in this macro invocation
|
||||||
|
|
|
||||||
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: cannot use a `block` macro fragment here
|
||||||
|
--> $DIR/bad-interpolated-block.rs:8:16
|
||||||
|
|
|
||||||
|
LL | unsafe $b;
|
||||||
|
| -------^^
|
||||||
|
| |
|
||||||
|
| the `block` fragment is within this context
|
||||||
|
...
|
||||||
|
LL | m!({});
|
||||||
|
| ------- in this macro invocation
|
||||||
|
|
|
||||||
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: cannot use a `block` macro fragment here
|
||||||
|
--> $DIR/bad-interpolated-block.rs:9:23
|
||||||
|
|
|
||||||
|
LL | |x: u8| -> () $b;
|
||||||
|
| ^^ the `block` fragment is within this context
|
||||||
|
...
|
||||||
|
LL | m!({});
|
||||||
|
| ------- in this macro invocation
|
||||||
|
|
|
||||||
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
31
src/test/ui/parser/block-no-opening-brace.rs
Normal file
31
src/test/ui/parser/block-no-opening-brace.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// edition:2018
|
||||||
|
|
||||||
|
#![feature(try_blocks)]
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
fn f1() {
|
||||||
|
loop
|
||||||
|
let x = 0; //~ ERROR expected `{`, found keyword `let`
|
||||||
|
drop(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f2() {
|
||||||
|
while true
|
||||||
|
let x = 0; //~ ERROR expected `{`, found keyword `let`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f3() {
|
||||||
|
for x in 0..1
|
||||||
|
let x = 0; //~ ERROR expected `{`, found keyword `let`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f4() {
|
||||||
|
try //~ ERROR expected expression, found reserved keyword `try`
|
||||||
|
let x = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f5() {
|
||||||
|
async //~ ERROR async closures are unstable
|
||||||
|
let x = 0; //~ ERROR expected one of `move`, `|`, or `||`, found keyword `let`
|
||||||
|
}
|
53
src/test/ui/parser/block-no-opening-brace.stderr
Normal file
53
src/test/ui/parser/block-no-opening-brace.stderr
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
error: expected `{`, found keyword `let`
|
||||||
|
--> $DIR/block-no-opening-brace.rs:9:9
|
||||||
|
|
|
||||||
|
LL | let x = 0;
|
||||||
|
| ^^^-------
|
||||||
|
| |
|
||||||
|
| expected `{`
|
||||||
|
| help: try placing this code inside a block: `{ let x = 0; }`
|
||||||
|
|
||||||
|
error: expected `{`, found keyword `let`
|
||||||
|
--> $DIR/block-no-opening-brace.rs:15:9
|
||||||
|
|
|
||||||
|
LL | let x = 0;
|
||||||
|
| ^^^-------
|
||||||
|
| |
|
||||||
|
| expected `{`
|
||||||
|
| help: try placing this code inside a block: `{ let x = 0; }`
|
||||||
|
|
||||||
|
error: expected `{`, found keyword `let`
|
||||||
|
--> $DIR/block-no-opening-brace.rs:20:9
|
||||||
|
|
|
||||||
|
LL | let x = 0;
|
||||||
|
| ^^^-------
|
||||||
|
| |
|
||||||
|
| expected `{`
|
||||||
|
| help: try placing this code inside a block: `{ let x = 0; }`
|
||||||
|
|
||||||
|
error: expected expression, found reserved keyword `try`
|
||||||
|
--> $DIR/block-no-opening-brace.rs:24:5
|
||||||
|
|
|
||||||
|
LL | try
|
||||||
|
| ^^^ expected expression
|
||||||
|
|
||||||
|
error: expected one of `move`, `|`, or `||`, found keyword `let`
|
||||||
|
--> $DIR/block-no-opening-brace.rs:30:9
|
||||||
|
|
|
||||||
|
LL | async
|
||||||
|
| - expected one of `move`, `|`, or `||`
|
||||||
|
LL | let x = 0;
|
||||||
|
| ^^^ unexpected token
|
||||||
|
|
||||||
|
error[E0658]: async closures are unstable
|
||||||
|
--> $DIR/block-no-opening-brace.rs:29:5
|
||||||
|
|
|
||||||
|
LL | async
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #62290 <https://github.com/rust-lang/rust/issues/62290> for more information
|
||||||
|
= help: add `#![feature(async_closure)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
|
@ -6,6 +6,6 @@ type A = for<'a: 'b + 'c> fn(); // OK (rejected later by ast_validation)
|
||||||
type A = for<'a: 'b,> fn(); // OK(rejected later by ast_validation)
|
type A = for<'a: 'b,> fn(); // OK(rejected later by ast_validation)
|
||||||
type A = for<'a: 'b +> fn(); // OK (rejected later by ast_validation)
|
type A = for<'a: 'b +> fn(); // OK (rejected later by ast_validation)
|
||||||
type A = for<'a, T> fn(); // OK (rejected later by ast_validation)
|
type A = for<'a, T> fn(); // OK (rejected later by ast_validation)
|
||||||
type A = for<,> fn(); //~ ERROR expected one of `>`, `const`, identifier, or lifetime, found `,`
|
type A = for<,> fn(); //~ ERROR expected one of `#`, `>`, `const`, identifier, or lifetime
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: expected one of `>`, `const`, identifier, or lifetime, found `,`
|
error: expected one of `#`, `>`, `const`, identifier, or lifetime, found `,`
|
||||||
--> $DIR/bounds-lifetime.rs:9:14
|
--> $DIR/bounds-lifetime.rs:9:14
|
||||||
|
|
|
|
||||||
LL | type A = for<,> fn();
|
LL | type A = for<,> fn();
|
||||||
| ^ expected one of `>`, `const`, identifier, or lifetime
|
| ^ expected one of `#`, `>`, `const`, identifier, or lifetime
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -3,5 +3,5 @@
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = || -> i32 22;
|
let x = || -> i32 22;
|
||||||
//~^ ERROR expected one of `!`, `(`, `+`, `::`, `<`, or `{`, found `22`
|
//~^ ERROR expected `{`, found `22`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
error: expected one of `!`, `(`, `+`, `::`, `<`, or `{`, found `22`
|
error: expected `{`, found `22`
|
||||||
--> $DIR/closure-return-syntax.rs:5:23
|
--> $DIR/closure-return-syntax.rs:5:23
|
||||||
|
|
|
|
||||||
LL | let x = || -> i32 22;
|
LL | let x = || -> i32 22;
|
||||||
| ^^ expected one of `!`, `(`, `+`, `::`, `<`, or `{`
|
| ^^
|
||||||
|
| |
|
||||||
|
| expected `{`
|
||||||
|
| help: try placing this code inside a block: `{ 22 }`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
# //~ ERROR expected `[`, found `<eof>`
|
# //~ ERROR expected one of `!` or `[`, found `<eof>`
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: expected `[`, found `<eof>`
|
error: expected one of `!` or `[`, found `<eof>`
|
||||||
--> $DIR/column-offset-1-based.rs:1:1
|
--> $DIR/column-offset-1-based.rs:1:1
|
||||||
|
|
|
|
||||||
LL | #
|
LL | #
|
||||||
| ^ expected `[`
|
| ^ expected one of `!` or `[`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
if true /*!*/ {}
|
if true /*!*/ {}
|
||||||
//~^ ERROR expected `{`, found doc comment `/*!*/`
|
//~^ ERROR outer attributes are not allowed on
|
||||||
|
//~| ERROR expected outer doc comment
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,19 @@
|
||||||
error: expected `{`, found doc comment `/*!*/`
|
error: expected outer doc comment
|
||||||
--> $DIR/doc-comment-in-if-statement.rs:2:13
|
--> $DIR/doc-comment-in-if-statement.rs:2:13
|
||||||
|
|
|
|
||||||
LL | if true /*!*/ {}
|
LL | if true /*!*/ {}
|
||||||
| -- ^^^^^ expected `{`
|
| ^^^^^
|
||||||
| |
|
|
|
||||||
| this `if` expression has a condition, but no block
|
= note: inner doc comments like this (starting with `//!` or `/*!`) can only appear before items
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: outer attributes are not allowed on `if` and `else` branches
|
||||||
|
--> $DIR/doc-comment-in-if-statement.rs:2:13
|
||||||
|
|
|
||||||
|
LL | if true /*!*/ {}
|
||||||
|
| -- ^^^^^ -- the attributes are attached to this branch
|
||||||
|
| | |
|
||||||
|
| | help: remove the attributes
|
||||||
|
| the branch belongs to this `if`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
23
src/test/ui/parser/fn-body-eq-expr-semi.rs
Normal file
23
src/test/ui/parser/fn-body-eq-expr-semi.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
fn syntax() {
|
||||||
|
fn foo() = 42; //~ ERROR function body cannot be `= expression;`
|
||||||
|
fn bar() -> u8 = 42; //~ ERROR function body cannot be `= expression;`
|
||||||
|
}
|
||||||
|
|
||||||
|
extern {
|
||||||
|
fn foo() = 42; //~ ERROR function body cannot be `= expression;`
|
||||||
|
//~^ ERROR incorrect function inside `extern` block
|
||||||
|
fn bar() -> u8 = 42; //~ ERROR function body cannot be `= expression;`
|
||||||
|
//~^ ERROR incorrect function inside `extern` block
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
fn foo() = 42; //~ ERROR function body cannot be `= expression;`
|
||||||
|
fn bar() -> u8 = 42; //~ ERROR function body cannot be `= expression;`
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Foo for () {
|
||||||
|
fn foo() = 42; //~ ERROR function body cannot be `= expression;`
|
||||||
|
fn bar() -> u8 = 42; //~ ERROR function body cannot be `= expression;`
|
||||||
|
}
|
117
src/test/ui/parser/fn-body-eq-expr-semi.stderr
Normal file
117
src/test/ui/parser/fn-body-eq-expr-semi.stderr
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
error: function body cannot be `= expression;`
|
||||||
|
--> $DIR/fn-body-eq-expr-semi.rs:4:14
|
||||||
|
|
|
||||||
|
LL | fn foo() = 42;
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
help: surround the expression with `{` and `}` instead of `=` and `;`
|
||||||
|
|
|
||||||
|
LL | fn foo() { 42 }
|
||||||
|
| ^ ^
|
||||||
|
|
||||||
|
error: function body cannot be `= expression;`
|
||||||
|
--> $DIR/fn-body-eq-expr-semi.rs:5:20
|
||||||
|
|
|
||||||
|
LL | fn bar() -> u8 = 42;
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
help: surround the expression with `{` and `}` instead of `=` and `;`
|
||||||
|
|
|
||||||
|
LL | fn bar() -> u8 { 42 }
|
||||||
|
| ^ ^
|
||||||
|
|
||||||
|
error: function body cannot be `= expression;`
|
||||||
|
--> $DIR/fn-body-eq-expr-semi.rs:9:14
|
||||||
|
|
|
||||||
|
LL | fn foo() = 42;
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
help: surround the expression with `{` and `}` instead of `=` and `;`
|
||||||
|
|
|
||||||
|
LL | fn foo() { 42 }
|
||||||
|
| ^ ^
|
||||||
|
|
||||||
|
error: function body cannot be `= expression;`
|
||||||
|
--> $DIR/fn-body-eq-expr-semi.rs:11:20
|
||||||
|
|
|
||||||
|
LL | fn bar() -> u8 = 42;
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
help: surround the expression with `{` and `}` instead of `=` and `;`
|
||||||
|
|
|
||||||
|
LL | fn bar() -> u8 { 42 }
|
||||||
|
| ^ ^
|
||||||
|
|
||||||
|
error: function body cannot be `= expression;`
|
||||||
|
--> $DIR/fn-body-eq-expr-semi.rs:16:14
|
||||||
|
|
|
||||||
|
LL | fn foo() = 42;
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
help: surround the expression with `{` and `}` instead of `=` and `;`
|
||||||
|
|
|
||||||
|
LL | fn foo() { 42 }
|
||||||
|
| ^ ^
|
||||||
|
|
||||||
|
error: function body cannot be `= expression;`
|
||||||
|
--> $DIR/fn-body-eq-expr-semi.rs:17:20
|
||||||
|
|
|
||||||
|
LL | fn bar() -> u8 = 42;
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
help: surround the expression with `{` and `}` instead of `=` and `;`
|
||||||
|
|
|
||||||
|
LL | fn bar() -> u8 { 42 }
|
||||||
|
| ^ ^
|
||||||
|
|
||||||
|
error: function body cannot be `= expression;`
|
||||||
|
--> $DIR/fn-body-eq-expr-semi.rs:21:14
|
||||||
|
|
|
||||||
|
LL | fn foo() = 42;
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
help: surround the expression with `{` and `}` instead of `=` and `;`
|
||||||
|
|
|
||||||
|
LL | fn foo() { 42 }
|
||||||
|
| ^ ^
|
||||||
|
|
||||||
|
error: function body cannot be `= expression;`
|
||||||
|
--> $DIR/fn-body-eq-expr-semi.rs:22:20
|
||||||
|
|
|
||||||
|
LL | fn bar() -> u8 = 42;
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
help: surround the expression with `{` and `}` instead of `=` and `;`
|
||||||
|
|
|
||||||
|
LL | fn bar() -> u8 { 42 }
|
||||||
|
| ^ ^
|
||||||
|
|
||||||
|
error: incorrect function inside `extern` block
|
||||||
|
--> $DIR/fn-body-eq-expr-semi.rs:9:8
|
||||||
|
|
|
||||||
|
LL | extern {
|
||||||
|
| ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body
|
||||||
|
LL | fn foo() = 42;
|
||||||
|
| ^^^ ----- help: remove the invalid body: `;`
|
||||||
|
| |
|
||||||
|
| cannot have a body
|
||||||
|
|
|
||||||
|
= help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
|
||||||
|
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
|
||||||
|
|
||||||
|
error: incorrect function inside `extern` block
|
||||||
|
--> $DIR/fn-body-eq-expr-semi.rs:11:8
|
||||||
|
|
|
||||||
|
LL | extern {
|
||||||
|
| ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body
|
||||||
|
...
|
||||||
|
LL | fn bar() -> u8 = 42;
|
||||||
|
| ^^^ ----- help: remove the invalid body: `;`
|
||||||
|
| |
|
||||||
|
| cannot have a body
|
||||||
|
|
|
||||||
|
= help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
|
||||||
|
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
|
||||||
|
|
||||||
|
error: aborting due to 10 previous errors
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// error-pattern:expected `[`, found `vec`
|
|
||||||
mod blade_runner {
|
mod blade_runner {
|
||||||
#vec[doc(
|
#vec[doc( //~ ERROR expected one of `!` or `[`, found `vec`
|
||||||
brief = "Blade Runner is probably the best movie ever",
|
brief = "Blade Runner is probably the best movie ever",
|
||||||
desc = "I like that in the world of Blade Runner it is always
|
desc = "I like that in the world of Blade Runner it is always
|
||||||
raining, and that it's always night time. And Aliens
|
raining, and that it's always night time. And Aliens
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: expected `[`, found `vec`
|
error: expected one of `!` or `[`, found `vec`
|
||||||
--> $DIR/issue-1655.rs:3:6
|
--> $DIR/issue-1655.rs:2:6
|
||||||
|
|
|
|
||||||
LL | #vec[doc(
|
LL | #vec[doc(
|
||||||
| ^^^ expected `[`
|
| ^^^ expected one of `!` or `[`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `;`
|
||||||
LL | impl W <s(f;Y(;]
|
LL | impl W <s(f;Y(;]
|
||||||
| ^ expected one of 7 possible tokens
|
| ^ expected one of 7 possible tokens
|
||||||
|
|
||||||
error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `<`, `>`, `?`, `[`, `_`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, or lifetime, found `;`
|
error: expected one of `!`, `&&`, `&`, `(`, `)`, `*`, `+`, `,`, `->`, `...`, `::`, `<`, `>`, `?`, `[`, `_`, `dyn`, `extern`, `fn`, `for`, `impl`, `unsafe`, lifetime, or path, found `;`
|
||||||
--> $DIR/issue-63116.rs:3:15
|
--> $DIR/issue-63116.rs:3:15
|
||||||
|
|
|
|
||||||
LL | impl W <s(f;Y(;]
|
LL | impl W <s(f;Y(;]
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
// error-pattern: aborting due to 7 previous errors
|
// error-pattern: aborting due to 5 previous errors
|
||||||
|
|
||||||
fn i(n{...,f #
|
fn i(n{...,f #
|
||||||
|
|
|
@ -31,23 +31,11 @@ LL | fn i(n{...,f #
|
||||||
| | expected `}`
|
| | expected `}`
|
||||||
| `..` must be at the end and cannot have a trailing comma
|
| `..` must be at the end and cannot have a trailing comma
|
||||||
|
|
||||||
error: expected `[`, found `}`
|
error: expected one of `!` or `[`, found `}`
|
||||||
--> $DIR/issue-63135.rs:3:16
|
--> $DIR/issue-63135.rs:3:16
|
||||||
|
|
|
|
||||||
LL | fn i(n{...,f #
|
LL | fn i(n{...,f #
|
||||||
| ^ expected `[`
|
| ^ expected one of `!` or `[`
|
||||||
|
|
||||||
error: expected one of `:` or `|`, found `)`
|
error: aborting due to 5 previous errors
|
||||||
--> $DIR/issue-63135.rs:3:16
|
|
||||||
|
|
|
||||||
LL | fn i(n{...,f #
|
|
||||||
| ^ expected one of `:` or `|`
|
|
||||||
|
|
||||||
error: expected `;` or `{`, found `<eof>`
|
|
||||||
--> $DIR/issue-63135.rs:3:16
|
|
||||||
|
|
|
||||||
LL | fn i(n{...,f #
|
|
||||||
| ^ expected `;` or `{`
|
|
||||||
|
|
||||||
error: aborting due to 7 previous errors
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
6
src/test/ui/parser/issue-68890-2.rs
Normal file
6
src/test/ui/parser/issue-68890-2.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
fn main() {}
|
||||||
|
|
||||||
|
type X<'a> = (?'a) +;
|
||||||
|
//~^ ERROR `?` may only modify trait bounds, not lifetime bounds
|
||||||
|
//~| ERROR at least one trait is required for an object type
|
||||||
|
//~| WARN trait objects without an explicit `dyn` are deprecated
|
22
src/test/ui/parser/issue-68890-2.stderr
Normal file
22
src/test/ui/parser/issue-68890-2.stderr
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
error: `?` may only modify trait bounds, not lifetime bounds
|
||||||
|
--> $DIR/issue-68890-2.rs:3:15
|
||||||
|
|
|
||||||
|
LL | type X<'a> = (?'a) +;
|
||||||
|
| ^
|
||||||
|
|
||||||
|
warning: trait objects without an explicit `dyn` are deprecated
|
||||||
|
--> $DIR/issue-68890-2.rs:3:14
|
||||||
|
|
|
||||||
|
LL | type X<'a> = (?'a) +;
|
||||||
|
| ^^^^^^^ help: use `dyn`: `dyn (?'a) +`
|
||||||
|
|
|
||||||
|
= note: `#[warn(bare_trait_objects)]` on by default
|
||||||
|
|
||||||
|
error[E0224]: at least one trait is required for an object type
|
||||||
|
--> $DIR/issue-68890-2.rs:3:14
|
||||||
|
|
|
||||||
|
LL | type X<'a> = (?'a) +;
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
enum e{A((?'a a+?+l))}
|
enum e{A((?'a a+?+l))}
|
||||||
//~^ ERROR `?` may only modify trait bounds, not lifetime bounds
|
//~^ ERROR `?` may only modify trait bounds, not lifetime bounds
|
||||||
//~| ERROR expected one of `)`, `+`, or `,`
|
//~| ERROR expected one of `)`, `+`, or `,`
|
||||||
//~| ERROR expected trait bound, not lifetime bound
|
//~| ERROR expected item, found `)`
|
||||||
|
|
|
@ -10,11 +10,11 @@ error: expected one of `)`, `+`, or `,`, found `a`
|
||||||
LL | enum e{A((?'a a+?+l))}
|
LL | enum e{A((?'a a+?+l))}
|
||||||
| ^ expected one of `)`, `+`, or `,`
|
| ^ expected one of `)`, `+`, or `,`
|
||||||
|
|
||||||
error: expected trait bound, not lifetime bound
|
error: expected item, found `)`
|
||||||
--> $DIR/issue-68890.rs:1:11
|
--> $DIR/issue-68890.rs:1:21
|
||||||
|
|
|
|
||||||
LL | enum e{A((?'a a+?+l))}
|
LL | enum e{A((?'a a+?+l))}
|
||||||
| ^^^
|
| ^ expected item
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
17
src/test/ui/parser/labeled-no-colon-expr.rs
Normal file
17
src/test/ui/parser/labeled-no-colon-expr.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#![feature(label_break_value)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
'l0 while false {} //~ ERROR labeled expression must be followed by `:`
|
||||||
|
'l1 for _ in 0..1 {} //~ ERROR labeled expression must be followed by `:`
|
||||||
|
'l2 loop {} //~ ERROR labeled expression must be followed by `:`
|
||||||
|
'l3 {} //~ ERROR labeled expression must be followed by `:`
|
||||||
|
'l4 0; //~ ERROR labeled expression must be followed by `:`
|
||||||
|
//~^ ERROR expected `while`, `for`, `loop` or `{`
|
||||||
|
|
||||||
|
macro_rules! m {
|
||||||
|
($b:block) => {
|
||||||
|
'l5 $b; //~ ERROR cannot use a `block` macro fragment here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m!({}); //~ ERROR labeled expression must be followed by `:`
|
||||||
|
}
|
89
src/test/ui/parser/labeled-no-colon-expr.stderr
Normal file
89
src/test/ui/parser/labeled-no-colon-expr.stderr
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
error: labeled expression must be followed by `:`
|
||||||
|
--> $DIR/labeled-no-colon-expr.rs:4:5
|
||||||
|
|
|
||||||
|
LL | 'l0 while false {}
|
||||||
|
| ----^^^^^^^^^^^^^^
|
||||||
|
| | |
|
||||||
|
| | help: add `:` after the label
|
||||||
|
| the label
|
||||||
|
|
|
||||||
|
= note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
|
||||||
|
|
||||||
|
error: labeled expression must be followed by `:`
|
||||||
|
--> $DIR/labeled-no-colon-expr.rs:5:5
|
||||||
|
|
|
||||||
|
LL | 'l1 for _ in 0..1 {}
|
||||||
|
| ----^^^^^^^^^^^^^^^^
|
||||||
|
| | |
|
||||||
|
| | help: add `:` after the label
|
||||||
|
| the label
|
||||||
|
|
|
||||||
|
= note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
|
||||||
|
|
||||||
|
error: labeled expression must be followed by `:`
|
||||||
|
--> $DIR/labeled-no-colon-expr.rs:6:5
|
||||||
|
|
|
||||||
|
LL | 'l2 loop {}
|
||||||
|
| ----^^^^^^^
|
||||||
|
| | |
|
||||||
|
| | help: add `:` after the label
|
||||||
|
| the label
|
||||||
|
|
|
||||||
|
= note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
|
||||||
|
|
||||||
|
error: labeled expression must be followed by `:`
|
||||||
|
--> $DIR/labeled-no-colon-expr.rs:7:5
|
||||||
|
|
|
||||||
|
LL | 'l3 {}
|
||||||
|
| ----^^
|
||||||
|
| | |
|
||||||
|
| | help: add `:` after the label
|
||||||
|
| the label
|
||||||
|
|
|
||||||
|
= note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
|
||||||
|
|
||||||
|
error: expected `while`, `for`, `loop` or `{` after a label
|
||||||
|
--> $DIR/labeled-no-colon-expr.rs:8:9
|
||||||
|
|
|
||||||
|
LL | 'l4 0;
|
||||||
|
| ^ expected `while`, `for`, `loop` or `{` after a label
|
||||||
|
|
||||||
|
error: labeled expression must be followed by `:`
|
||||||
|
--> $DIR/labeled-no-colon-expr.rs:8:9
|
||||||
|
|
|
||||||
|
LL | 'l4 0;
|
||||||
|
| ----^
|
||||||
|
| | |
|
||||||
|
| | help: add `:` after the label
|
||||||
|
| the label
|
||||||
|
|
|
||||||
|
= note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
|
||||||
|
|
||||||
|
error: cannot use a `block` macro fragment here
|
||||||
|
--> $DIR/labeled-no-colon-expr.rs:13:17
|
||||||
|
|
|
||||||
|
LL | 'l5 $b;
|
||||||
|
| ----^^
|
||||||
|
| |
|
||||||
|
| the `block` fragment is within this context
|
||||||
|
...
|
||||||
|
LL | m!({});
|
||||||
|
| ------- in this macro invocation
|
||||||
|
|
|
||||||
|
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error: labeled expression must be followed by `:`
|
||||||
|
--> $DIR/labeled-no-colon-expr.rs:16:8
|
||||||
|
|
|
||||||
|
LL | 'l5 $b;
|
||||||
|
| ---- help: add `:` after the label
|
||||||
|
| |
|
||||||
|
| the label
|
||||||
|
...
|
||||||
|
LL | m!({});
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
|
||||||
|
|
||||||
|
error: aborting due to 8 previous errors
|
||||||
|
|
|
@ -2,9 +2,14 @@
|
||||||
// `ty` matcher in particular doesn't accept a single lifetime
|
// `ty` matcher in particular doesn't accept a single lifetime
|
||||||
|
|
||||||
macro_rules! m {
|
macro_rules! m {
|
||||||
($t: ty) => ( let _: $t; )
|
($t: ty) => {
|
||||||
|
let _: $t;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
m!('static); //~ ERROR expected type, found `'static`
|
m!('static);
|
||||||
|
//~^ ERROR lifetime in trait object type must be followed by `+`
|
||||||
|
//~| ERROR at least one trait is required for an object type
|
||||||
|
//~| WARN trait objects without an explicit `dyn` are deprecated
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,22 @@
|
||||||
error: expected type, found `'static`
|
error: lifetime in trait object type must be followed by `+`
|
||||||
--> $DIR/trait-object-macro-matcher.rs:9:8
|
--> $DIR/trait-object-macro-matcher.rs:11:8
|
||||||
|
|
|
|
||||||
LL | m!('static);
|
LL | m!('static);
|
||||||
| ^^^^^^^ expected type
|
| ^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
warning: trait objects without an explicit `dyn` are deprecated
|
||||||
|
--> $DIR/trait-object-macro-matcher.rs:11:8
|
||||||
|
|
|
||||||
|
LL | m!('static);
|
||||||
|
| ^^^^^^^ help: use `dyn`: `dyn 'static`
|
||||||
|
|
|
||||||
|
= note: `#[warn(bare_trait_objects)]` on by default
|
||||||
|
|
||||||
|
error[E0224]: at least one trait is required for an object type
|
||||||
|
--> $DIR/trait-object-macro-matcher.rs:11:8
|
||||||
|
|
|
||||||
|
LL | m!('static);
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ fn foo(cond: bool) {
|
||||||
let mut x;
|
let mut x;
|
||||||
|
|
||||||
if cond {
|
if cond {
|
||||||
x = &'blk [1,2,3]; //~ ERROR expected `:`, found `[`
|
x = &'blk [1,2,3]; //~ ERROR borrow expressions cannot be annotated with lifetimes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
error: expected `:`, found `[`
|
error: borrow expressions cannot be annotated with lifetimes
|
||||||
--> $DIR/regions-out-of-scope-slice.rs:7:19
|
--> $DIR/regions-out-of-scope-slice.rs:7:13
|
||||||
|
|
|
|
||||||
LL | x = &'blk [1,2,3];
|
LL | x = &'blk [1,2,3];
|
||||||
| ^ expected `:`
|
| ^----^^^^^^^^
|
||||||
|
| |
|
||||||
|
| annotated with lifetime here
|
||||||
|
| help: remove the lifetime annotation
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,7 @@ fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not s
|
||||||
|
|
||||||
fn check<'a>() {
|
fn check<'a>() {
|
||||||
let _: Box<Trait + ('a)>; //~ ERROR parenthesized lifetime bounds are not supported
|
let _: Box<Trait + ('a)>; //~ ERROR parenthesized lifetime bounds are not supported
|
||||||
let _: Box<('a) + Trait>;
|
let _: Box<('a) + Trait>; //~ ERROR lifetime in trait object type must be followed by `+`
|
||||||
//~^ ERROR expected type, found `'a`
|
|
||||||
//~| ERROR expected `:`, found `)`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -10,19 +10,11 @@ error: parenthesized lifetime bounds are not supported
|
||||||
LL | let _: Box<Trait + ('a)>;
|
LL | let _: Box<Trait + ('a)>;
|
||||||
| ^^^^ help: remove the parentheses
|
| ^^^^ help: remove the parentheses
|
||||||
|
|
||||||
error: expected `:`, found `)`
|
error: lifetime in trait object type must be followed by `+`
|
||||||
--> $DIR/trait-object-lifetime-parens.rs:9:19
|
|
||||||
|
|
|
||||||
LL | let _: Box<('a) + Trait>;
|
|
||||||
| ^ expected `:`
|
|
||||||
|
|
||||||
error: expected type, found `'a`
|
|
||||||
--> $DIR/trait-object-lifetime-parens.rs:9:17
|
--> $DIR/trait-object-lifetime-parens.rs:9:17
|
||||||
|
|
|
|
||||||
LL | let _: Box<('a) + Trait>;
|
LL | let _: Box<('a) + Trait>;
|
||||||
| - ^^ expected type
|
| ^^
|
||||||
| |
|
|
||||||
| while parsing the type for `_`
|
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
trait Trait<'a> {}
|
trait Trait<'a> {}
|
||||||
|
|
||||||
|
trait Obj {}
|
||||||
|
|
||||||
fn f<T: (Copy) + (?Sized) + (for<'a> Trait<'a>)>() {}
|
fn f<T: (Copy) + (?Sized) + (for<'a> Trait<'a>)>() {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>;
|
let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
|
||||||
//~^ ERROR `?Trait` is not permitted in trait object types
|
//~^ ERROR `?Trait` is not permitted in trait object types
|
||||||
|
//~| ERROR only auto traits can be used as additional traits
|
||||||
//~| WARN trait objects without an explicit `dyn` are deprecated
|
//~| WARN trait objects without an explicit `dyn` are deprecated
|
||||||
let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>;
|
let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>;
|
||||||
//~^ WARN trait objects without an explicit `dyn` are deprecated
|
//~^ ERROR `?Trait` is not permitted in trait object types
|
||||||
let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>;
|
//~| ERROR only auto traits can be used as additional traits
|
||||||
//~^ ERROR use of undeclared lifetime name `'a`
|
//~| WARN trait objects without an explicit `dyn` are deprecated
|
||||||
//~| ERROR `?Trait` is not permitted in trait object types
|
let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>;
|
||||||
|
//~^ ERROR `?Trait` is not permitted in trait object types
|
||||||
|
//~| ERROR only auto traits can be used as additional traits
|
||||||
//~| WARN trait objects without an explicit `dyn` are deprecated
|
//~| WARN trait objects without an explicit `dyn` are deprecated
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,44 +1,74 @@
|
||||||
error: `?Trait` is not permitted in trait object types
|
error: `?Trait` is not permitted in trait object types
|
||||||
--> $DIR/trait-object-trait-parens.rs:6:25
|
--> $DIR/trait-object-trait-parens.rs:8:24
|
||||||
|
|
|
|
||||||
LL | let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>;
|
LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: `?Trait` is not permitted in trait object types
|
error: `?Trait` is not permitted in trait object types
|
||||||
--> $DIR/trait-object-trait-parens.rs:11:47
|
--> $DIR/trait-object-trait-parens.rs:12:17
|
||||||
|
|
|
|
||||||
LL | let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>;
|
LL | let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>;
|
||||||
|
| ^^^^^^
|
||||||
|
|
||||||
|
error: `?Trait` is not permitted in trait object types
|
||||||
|
--> $DIR/trait-object-trait-parens.rs:16:46
|
||||||
|
|
|
||||||
|
LL | let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
warning: trait objects without an explicit `dyn` are deprecated
|
warning: trait objects without an explicit `dyn` are deprecated
|
||||||
--> $DIR/trait-object-trait-parens.rs:6:16
|
--> $DIR/trait-object-trait-parens.rs:8:16
|
||||||
|
|
|
|
||||||
LL | let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>;
|
LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (Copy) + (?Sized) + (for<'a> Trait<'a>)`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (Obj) + (?Sized) + (for<'a> Trait<'a>)`
|
||||||
|
|
|
|
||||||
= note: `#[warn(bare_trait_objects)]` on by default
|
= note: `#[warn(bare_trait_objects)]` on by default
|
||||||
|
|
||||||
warning: trait objects without an explicit `dyn` are deprecated
|
warning: trait objects without an explicit `dyn` are deprecated
|
||||||
--> $DIR/trait-object-trait-parens.rs:9:16
|
--> $DIR/trait-object-trait-parens.rs:12:16
|
||||||
|
|
|
|
||||||
LL | let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>;
|
LL | let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (?Sized) + (for<'a> Trait<'a>) + (Copy)`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (?Sized) + (for<'a> Trait<'a>) + (Obj)`
|
||||||
|
|
||||||
warning: trait objects without an explicit `dyn` are deprecated
|
warning: trait objects without an explicit `dyn` are deprecated
|
||||||
--> $DIR/trait-object-trait-parens.rs:11:16
|
--> $DIR/trait-object-trait-parens.rs:16:16
|
||||||
|
|
|
|
||||||
LL | let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>;
|
LL | let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>;
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (for<'a> Trait<'a>) + (Copy) + (?Sized)`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn (for<'a> Trait<'a>) + (Obj) + (?Sized)`
|
||||||
|
|
||||||
error[E0261]: use of undeclared lifetime name `'a`
|
error[E0225]: only auto traits can be used as additional traits in a trait object
|
||||||
--> $DIR/trait-object-trait-parens.rs:11:31
|
--> $DIR/trait-object-trait-parens.rs:8:35
|
||||||
|
|
|
|
||||||
LL | fn main() {
|
LL | let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
|
||||||
| - help: consider introducing lifetime `'a` here: `<'a>`
|
| ----- ^^^^^^^^^^^^^^^^^^^
|
||||||
...
|
| | |
|
||||||
LL | let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>;
|
| | additional non-auto trait
|
||||||
| ^^ undeclared lifetime
|
| | trait alias used in trait object type (additional use)
|
||||||
|
| first non-auto trait
|
||||||
|
| trait alias used in trait object type (first use)
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error[E0225]: only auto traits can be used as additional traits in a trait object
|
||||||
|
--> $DIR/trait-object-trait-parens.rs:12:49
|
||||||
|
|
|
||||||
|
LL | let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Obj)>;
|
||||||
|
| ------------------- ^^^^^
|
||||||
|
| | |
|
||||||
|
| | additional non-auto trait
|
||||||
|
| | trait alias used in trait object type (additional use)
|
||||||
|
| first non-auto trait
|
||||||
|
| trait alias used in trait object type (first use)
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0261`.
|
error[E0225]: only auto traits can be used as additional traits in a trait object
|
||||||
|
--> $DIR/trait-object-trait-parens.rs:16:38
|
||||||
|
|
|
||||||
|
LL | let _: Box<(for<'a> Trait<'a>) + (Obj) + (?Sized)>;
|
||||||
|
| ----------------- ^^^^^
|
||||||
|
| | |
|
||||||
|
| | additional non-auto trait
|
||||||
|
| | trait alias used in trait object type (additional use)
|
||||||
|
| first non-auto trait
|
||||||
|
| trait alias used in trait object type (first use)
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0225`.
|
||||||
|
|
|
@ -8,3 +8,4 @@ LL | struct S;
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0739`.
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
error: expected `{`, found `std`
|
error: expected `{`, found `std`
|
||||||
--> $DIR/unsafe-block-without-braces.rs:3:9
|
--> $DIR/unsafe-block-without-braces.rs:3:9
|
||||||
|
|
|
|
||||||
LL | unsafe //{
|
|
||||||
| - expected `{`
|
|
||||||
LL | std::mem::transmute::<f32, u32>(1.0);
|
LL | std::mem::transmute::<f32, u32>(1.0);
|
||||||
| ^^^ unexpected token
|
| ^^^----------------------------------
|
||||||
|
| |
|
||||||
|
| expected `{`
|
||||||
|
| help: try placing this code inside a block: `{ std::mem::transmute::<f32, u32>(1.0); }`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -3204,7 +3204,9 @@ impl<'test> TestCx<'test> {
|
||||||
let json = cflags.contains("--error-format json")
|
let json = cflags.contains("--error-format json")
|
||||||
|| cflags.contains("--error-format pretty-json")
|
|| cflags.contains("--error-format pretty-json")
|
||||||
|| cflags.contains("--error-format=json")
|
|| cflags.contains("--error-format=json")
|
||||||
|| cflags.contains("--error-format=pretty-json");
|
|| cflags.contains("--error-format=pretty-json")
|
||||||
|
|| cflags.contains("--output-format json")
|
||||||
|
|| cflags.contains("--output-format=json");
|
||||||
|
|
||||||
let mut normalized = output.to_string();
|
let mut normalized = output.to_string();
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
//! Tidy checks source code in this repository.
|
//! Tidy checks source code in this repository.
|
||||||
//!
|
//!
|
||||||
//! This program runs all of the various tidy checks for style, cleanliness,
|
//! This program runs all of the various tidy checks for style, cleanliness,
|
||||||
//! etc. This is run by default on `make check` and as part of the auto
|
//! etc. This is run by default on `./x.py test` and as part of the auto
|
||||||
//! builders.
|
//! builders. The tidy checks can be executed with `./x.py test tidy`.
|
||||||
|
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue