1
Fork 0

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:
bors 2020-03-11 13:05:52 +00:00
commit c20d7eecbc
92 changed files with 1264 additions and 513 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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" { }
// Print it now. });
print_backtrace(&mut backtrace);
None let backtrace = match capture_backtrace {
} else { CtfeBacktrace::Disabled => None,
Some(Box::new(backtrace)) CtfeBacktrace::Capture => Some(Box::new(Backtrace::new_unresolved())),
} CtfeBacktrace::Immediate => {
// Print it now.
let mut backtrace = Backtrace::new_unresolved();
print_backtrace(&mut backtrace);
None
} }
_ => None,
}; };
InterpErrorInfo { kind, backtrace } InterpErrorInfo { kind, backtrace }
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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,48 +31,44 @@ 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() { "an inner attribute is not permitted following an outer attribute"
"an inner attribute is not permitted following an outer attribute" } else {
} else { DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG };
}; let inner_parse_policy = InnerAttrPolicy::Forbidden {
let inner_parse_policy = InnerAttributeParsePolicy::NotPermitted { 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), };
}; 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 {
} let attr = self.mk_doc_comment(s);
token::DocComment(s) => { if attr.style != ast::AttrStyle::Outer {
let attr = self.mk_doc_comment(s); self.struct_span_err(self.token.span, "expected outer doc comment")
if attr.style != ast::AttrStyle::Outer { .note(
let span = self.token.span;
let mut err = self.struct_span_err(span, "expected outer doc comment");
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);
self.bump();
just_parsed_doc_comment = true;
} }
_ => break, attrs.push(attr);
self.bump();
just_parsed_doc_comment = true;
} else {
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 { let lo = self.token.span;
token::Pound => { let (span, item, style) = if self.eat(&token::Pound) {
let lo = self.token.span; let style =
self.bump(); if self.eat(&token::Not) { ast::AttrStyle::Inner } else { ast::AttrStyle::Outer };
if let InnerAttributeParsePolicy::Permitted = inner_parse_policy { self.expect(&token::OpenDelim(token::Bracket))?;
self.expected_tokens.push(TokenType::Token(token::Not)); let item = self.parse_attr_item()?;
} self.expect(&token::CloseDelim(token::Bracket))?;
let attr_sp = lo.to(self.prev_token.span);
let style = if self.token == token::Not { // Emit error if inner attribute is encountered and forbidden.
self.bump(); if style == ast::AttrStyle::Inner {
ast::AttrStyle::Inner self.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy);
} else {
ast::AttrStyle::Outer
};
self.expect(&token::OpenDelim(token::Bracket))?;
let item = self.parse_attr_item()?;
self.expect(&token::CloseDelim(token::Bracket))?;
let hi = self.prev_token.span;
let attr_sp = lo.to(hi);
// Emit error if inner attribute is encountered and not permitted
if style == ast::AttrStyle::Inner {
if let InnerAttributeParsePolicy::NotPermitted {
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)
}
_ => {
let token_str = pprust::token_to_string(&self.token);
let msg = &format!("expected `#`, found `{}`", token_str);
return Err(self.struct_span_err(self.token.span, msg));
} }
(attr_sp, item, style)
} else {
let token_str = pprust::token_to_string(&self.token);
let msg = &format!("expected `#`, found `{}`", token_str);
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,28 +173,22 @@ 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. let attr = self.parse_attribute(true)?;
if !self.look_ahead(1, |t| t == &token::Not) { assert_eq!(attr.style, ast::AttrStyle::Inner);
break; attrs.push(attr);
} } else if let token::DocComment(s) = self.token.kind {
// We need to get the position of this token before we bump.
let attr = self.parse_attribute(true)?; let attr = self.mk_doc_comment(s);
assert_eq!(attr.style, ast::AttrStyle::Inner); if attr.style == ast::AttrStyle::Inner {
attrs.push(attr); attrs.push(attr);
self.bump();
} else {
break;
} }
token::DocComment(s) => { } else {
// We need to get the position of this token before we bump. break;
let attr = self.mk_doc_comment(s);
if attr.style == ast::AttrStyle::Inner {
attrs.push(attr);
self.bump();
} 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();
} }

View file

@ -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";
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`.
self.parse_expr()
}?;
if !ate_colon {
self.error_labeled_expr_must_be_followed_by_colon(lo, expr.span);
} }
let msg = "expected `while`, `for`, `loop` or `{` after a label"; Ok(expr)
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`.
self.parse_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).

View file

@ -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() {
} self.parse_inner_attrs_and_block().map(|(attrs, body)| (attrs, Some(body)))?
token::OpenDelim(token::Brace) => { } else if self.token.kind == token::Eq {
let (attrs, body) = self.parse_inner_attrs_and_block()?; // Recover `fn foo() = $expr;`.
(attrs, Some(body)) self.bump(); // `=`
} let eq_sp = self.prev_token.span;
token::Interpolated(ref nt) => match **nt { let _ = self.parse_expr()?;
token::NtBlock(..) => { self.expect_semi()?; // `;`
let (attrs, body) = self.parse_inner_attrs_and_block()?; let span = eq_sp.to(self.prev_token.span);
(attrs, Some(body)) self.struct_span_err(span, "function body cannot be `= expression;`")
} .multipart_suggestion(
_ => return self.expected_semi_or_open_brace(), "surround the expression with `{` and `}` instead of `=` and `;`",
}, vec![(eq_sp, "{".to_string()), (self.prev_token.span, " }".to_string())],
_ => return self.expected_semi_or_open_brace(), 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)

View file

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

View file

@ -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 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.
Ok(Some(_))
if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace)) if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace))
|| do_not_suggest_help || do_not_suggest_help => {}
{ Ok(Some(stmt)) => {
// If the next token is an open brace (e.g., `if a b {`), the place- let stmt_own_line = self.sess.source_map().is_line_before_span_empty(sp);
// inside-a-block suggestion would be more likely wrong than right. let stmt_span = if stmt_own_line && self.eat(&token::Semi) {
e.span_label(sp, "expected `{`");
return Err(e);
}
let stmt_span = if 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 {

View file

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

View file

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

View file

@ -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)?;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -112,20 +112,22 @@ 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
); );
} }
extern "C" LLVMValueRef extern "C" LLVMValueRef
@ -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,

View file

@ -0,0 +1,4 @@
// compile-flags:-Z unstable-options --output-format html --show-coverage
/// Foo
pub struct Xo;

View file

@ -0,0 +1,2 @@
error: html output format isn't supported for the --show-coverage option

View 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,
}

View file

@ -0,0 +1 @@
{"$DIR/json.rs":{"total":13,"with_docs":7}}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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!({});
}

View 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

View 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`
}

View 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`.

View file

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

View file

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

View file

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

View file

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

View file

@ -1 +1 @@
# //~ ERROR expected `[`, found `<eof>` # //~ ERROR expected one of `!` or `[`, found `<eof>`

View file

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

View file

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

View file

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

View 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;`
}

View 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

View file

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

View file

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

View file

@ -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(;]

View file

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

View file

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

View 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

View 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

View file

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

View file

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

View 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 `:`
}

View 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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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();

View file

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