Auto merge of #67091 - JohnTitor:rollup-kitphze, r=JohnTitor

Rollup of 11 pull requests

Successful merges:

 - #66846 (Make try_mark_previous_green aware of cycles.)
 - #66959 (Remove potential cfgs duplicates)
 - #66988 (Fix angle bracket formatting when dumping MIR debug vars)
 - #66998 (Modified the testcases for VxWorks)
 - #67008 (rustdoc: Add test for fixed issue)
 - #67023 (SGX: Fix target linker used by bootstrap)
 - #67033 (Migrate to LLVM{Get,Set}ValueName2)
 - #67049 (Simplify {IoSlice, IoSliceMut}::advance examples and tests)
 - #67054 (codegen "unreachable" for invalid SetDiscriminant)
 - #67081 (Fix Query type docs)
 - #67085 (Remove boxed closures in address parser.)

Failed merges:

r? @ghost
This commit is contained in:
bors 2019-12-06 15:11:35 +00:00
commit 9630dbbc3c
23 changed files with 214 additions and 101 deletions

View file

@ -810,6 +810,7 @@ impl Build {
!target.contains("emscripten") &&
!target.contains("wasm32") &&
!target.contains("nvptx") &&
!target.contains("fortanix") &&
!target.contains("fuchsia") {
Some(self.cc(target))
} else {

View file

@ -710,14 +710,25 @@ impl DepGraph {
return None
}
None => {
if !tcx.sess.has_errors() {
if !tcx.sess.has_errors_or_delayed_span_bugs() {
bug!("try_mark_previous_green() - Forcing the DepNode \
should have set its color")
} else {
// If the query we just forced has resulted
// in some kind of compilation error, we
// don't expect that the corresponding
// dep-node color has been updated.
// If the query we just forced has resulted in
// some kind of compilation error, we cannot rely on
// the dep-node color having been properly updated.
// This means that the query system has reached an
// invalid state. We let the compiler continue (by
// returning `None`) so it can emit error messages
// and wind down, but rely on the fact that this
// invalid state will not be persisted to the
// incremental compilation cache because of
// compilation errors being present.
debug!("try_mark_previous_green({:?}) - END - \
dependency {:?} resulted in compilation error",
dep_node,
dep_dep_node);
return None
}
}
}

View file

@ -22,7 +22,7 @@ use rustc_fs_util::{path_to_c_string, link_or_copy};
use rustc_data_structures::small_c_str::SmallCStr;
use errors::{Handler, FatalError};
use std::ffi::{CString, CStr};
use std::ffi::CString;
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
@ -833,8 +833,8 @@ fn create_msvc_imps(
})
.filter_map(|val| {
// Exclude some symbols that we know are not Rust symbols.
let name = CStr::from_ptr(llvm::LLVMGetValueName(val));
if ignored(name.to_bytes()) {
let name = llvm::get_value_name(val);
if ignored(name) {
None
} else {
Some((val, name))
@ -842,7 +842,7 @@ fn create_msvc_imps(
})
.map(move |(val, name)| {
let mut imp_name = prefix.as_bytes().to_vec();
imp_name.extend(name.to_bytes());
imp_name.extend(name);
let imp_name = CString::new(imp_name).unwrap();
(imp_name, val)
})

View file

@ -21,7 +21,7 @@ use rustc::ty::layout::{self, Size, Align, LayoutOf};
use rustc::hir::{self, CodegenFnAttrs, CodegenFnAttrFlags};
use std::ffi::{CStr, CString};
use std::ffi::CStr;
pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value {
let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
@ -392,16 +392,14 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
} else {
// If we created the global with the wrong type,
// correct the type.
let empty_string = const_cstr!("");
let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(g));
let name_string = CString::new(name_str_ref.to_bytes()).unwrap();
llvm::LLVMSetValueName(g, empty_string.as_ptr());
let name = llvm::get_value_name(g).to_vec();
llvm::set_value_name(g, b"");
let linkage = llvm::LLVMRustGetLinkage(g);
let visibility = llvm::LLVMRustGetVisibility(g);
let new_g = llvm::LLVMRustGetOrInsertGlobal(
self.llmod, name_string.as_ptr(), val_llty);
self.llmod, name.as_ptr().cast(), name.len(), val_llty);
llvm::LLVMRustSetLinkage(new_g, linkage);
llvm::LLVMRustSetVisibility(new_g, visibility);

View file

@ -32,7 +32,7 @@ use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, DebugScope,
use libc::c_uint;
use std::cell::RefCell;
use std::ffi::{CStr, CString};
use std::ffi::CString;
use smallvec::SmallVec;
use syntax_pos::{self, BytePos, Span, Pos};
@ -255,23 +255,11 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
return;
}
let old_name = unsafe {
CStr::from_ptr(llvm::LLVMGetValueName(value))
};
match old_name.to_str() {
Ok("") => {}
Ok(_) => {
// Avoid replacing the name if it already exists.
// While we could combine the names somehow, it'd
// get noisy quick, and the usefulness is dubious.
return;
}
Err(_) => return,
}
let cname = SmallCStr::new(name);
unsafe {
llvm::LLVMSetValueName(value, cname.as_ptr());
// Avoid replacing the name if it already exists.
// While we could combine the names somehow, it'd
// get noisy quick, and the usefulness is dubious.
if llvm::get_value_name(value).is_empty() {
llvm::set_value_name(value, name.as_bytes());
}
}
}

View file

@ -76,9 +76,8 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> {
name: &str, ty: &'ll Type
) -> &'ll Value {
debug!("declare_global(name={:?})", name);
let namebuf = SmallCStr::new(name);
unsafe {
llvm::LLVMRustGetOrInsertGlobal(self.llmod, namebuf.as_ptr(), ty)
llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_ptr().cast(), name.len(), ty)
}
}

View file

@ -701,8 +701,8 @@ extern "C" {
// Operations on all values
pub fn LLVMTypeOf(Val: &Value) -> &Type;
pub fn LLVMGetValueName(Val: &Value) -> *const c_char;
pub fn LLVMSetValueName(Val: &Value, Name: *const c_char);
pub fn LLVMGetValueName2(Val: &Value, Length: *mut size_t) -> *const c_char;
pub fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
pub fn LLVMReplaceAllUsesWith(OldVal: &'a Value, NewVal: &'a Value);
pub fn LLVMSetMetadata(Val: &'a Value, KindID: c_uint, Node: &'a Value);
@ -774,7 +774,8 @@ extern "C" {
pub fn LLVMIsAGlobalVariable(GlobalVar: &Value) -> Option<&Value>;
pub fn LLVMAddGlobal(M: &'a Module, Ty: &'a Type, Name: *const c_char) -> &'a Value;
pub fn LLVMGetNamedGlobal(M: &Module, Name: *const c_char) -> Option<&Value>;
pub fn LLVMRustGetOrInsertGlobal(M: &'a Module, Name: *const c_char, T: &'a Type) -> &'a Value;
pub fn LLVMRustGetOrInsertGlobal(M: &'a Module, Name: *const c_char, NameLen: size_t,
T: &'a Type) -> &'a Value;
pub fn LLVMRustInsertPrivateGlobal(M: &'a Module, T: &'a Type) -> &'a Value;
pub fn LLVMGetFirstGlobal(M: &Module) -> Option<&Value>;
pub fn LLVMGetNextGlobal(GlobalVar: &Value) -> Option<&Value>;
@ -1811,7 +1812,7 @@ extern "C" {
pub fn LLVMRustPositionBuilderAtStart(B: &Builder<'a>, BB: &'a BasicBlock);
pub fn LLVMRustSetComdat(M: &'a Module, V: &'a Value, Name: *const c_char);
pub fn LLVMRustSetComdat(M: &'a Module, V: &'a Value, Name: *const c_char, NameLen: size_t);
pub fn LLVMRustUnsetComdat(V: &Value);
pub fn LLVMRustSetModulePICLevel(M: &Module);
pub fn LLVMRustSetModulePIELevel(M: &Module);

View file

@ -115,7 +115,8 @@ pub fn SetFunctionCallConv(fn_: &'a Value, cc: CallConv) {
// For more details on COMDAT sections see e.g., http://www.airs.com/blog/archives/52
pub fn SetUniqueComdat(llmod: &Module, val: &'a Value) {
unsafe {
LLVMRustSetComdat(llmod, val, LLVMGetValueName(val));
let name = get_value_name(val);
LLVMRustSetComdat(llmod, val, name.as_ptr().cast(), name.len());
}
}
@ -217,6 +218,23 @@ pub fn get_param(llfn: &'a Value, index: c_uint) -> &'a Value {
}
}
/// Safe wrapper for `LLVMGetValueName2` into a byte slice
pub fn get_value_name(value: &'a Value) -> &'a [u8] {
unsafe {
let mut len = 0;
let data = LLVMGetValueName2(value, &mut len);
std::slice::from_raw_parts(data.cast(), len)
}
}
/// Safe wrapper for `LLVMSetValueName2` from a byte slice
pub fn set_value_name(value: &Value, name: &[u8]) {
unsafe {
let data = name.as_ptr().cast();
LLVMSetValueName2(value, data, name.len());
}
}
pub fn build_string(f: impl FnOnce(&RustString)) -> Result<String, FromUtf8Error> {
let sr = RustString {
bytes: RefCell::new(Vec::new()),

View file

@ -261,7 +261,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if self.fn_abi.ret.layout.abi.is_uninhabited() {
// Functions with uninhabited return values are marked `noreturn`,
// so we should make sure that we never actually do.
// We play it safe by using a well-defined `abort`, but we could go for immediate UB
// if that turns out to be helpful.
bx.abort();
// `abort` does not terminate the block, so we still need to generate
// an `unreachable` terminator after it.
bx.unreachable();
return;
}
@ -825,6 +829,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mir::TerminatorKind::Abort => {
bx.abort();
// `abort` does not terminate the block, so we still need to generate
// an `unreachable` terminator after it.
bx.unreachable();
}

View file

@ -475,9 +475,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
},
}
// Allow RalfJ to sleep soundly knowing that even refactorings that remove
// the above error (or silence it under some conditions) will not cause UB
// the above error (or silence it under some conditions) will not cause UB.
bx.abort();
// We've errored, so we don't have to produce working code.
// We still have to return an operand but it doesn't matter,
// this code is unreachable.
let ty = self.monomorphize(&constant.literal.ty);
let layout = bx.cx().layout_of(ty);
bx.load_operand(PlaceRef::new_sized(

View file

@ -333,6 +333,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
variant_index: VariantIdx
) {
if self.layout.for_variant(bx.cx(), variant_index).abi.is_uninhabited() {
// We play it safe by using a well-defined `abort`, but we could go for immediate UB
// if that turns out to be helpful.
bx.abort();
return;
}
match self.layout.variants {
@ -488,10 +491,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
},
Err(_) => {
// This is unreachable as long as runtime
// and compile-time agree on values
// and compile-time agree perfectly.
// With floats that won't always be true,
// so we generate an abort.
// so we generate a (safe) abort.
bx.abort();
// We still have to return a place but it doesn't matter,
// this code is unreachable.
let llval = bx.cx().const_undef(
bx.cx().type_ptr_to(bx.cx().backend_type(layout))
);

View file

@ -22,7 +22,7 @@ use std::mem;
use syntax::{self, ast};
/// Represent the result of a query.
/// This result can be stolen with the `take` method and returned with the `give` method.
/// This result can be stolen with the `take` method and generated with the `compute` method.
pub struct Query<T> {
result: RefCell<Option<Result<T>>>,
}
@ -37,7 +37,7 @@ impl<T> Query<T> {
}
/// Takes ownership of the query result. Further attempts to take or peek the query
/// result will panic unless it is returned by calling the `give` method.
/// result will panic unless it is generated by calling the `compute` method.
pub fn take(&self) -> T {
self.result
.borrow_mut()

View file

@ -202,7 +202,7 @@ fn write_graph_label<'tcx, W: Write>(
}
for var_debug_info in &body.var_debug_info {
write!(w, r#"debug {} => {};<br align="left"/>"#,
write!(w, r#"debug {} =&gt; {};<br align="left"/>"#,
var_debug_info.name, escape(&var_debug_info.place))?;
}

View file

@ -209,6 +209,9 @@ impl ops::Not for Cfg {
impl ops::BitAndAssign for Cfg {
fn bitand_assign(&mut self, other: Cfg) {
if *self == other {
return;
}
match (self, other) {
(&mut Cfg::False, _) | (_, Cfg::True) => {},
(s, Cfg::False) => *s = Cfg::False,
@ -238,6 +241,9 @@ impl ops::BitAnd for Cfg {
impl ops::BitOrAssign for Cfg {
fn bitor_assign(&mut self, other: Cfg) {
if *self == other {
return;
}
match (self, other) {
(&mut Cfg::True, _) | (_, Cfg::False) => {},
(s, Cfg::True) => *s = Cfg::True,

View file

@ -2339,8 +2339,10 @@ mod tests {
let filename = &tmpdir.join("file_that_does_not_exist.txt");
let result = File::open(filename);
#[cfg(unix)]
#[cfg(all(unix, not(target_os = "vxworks")))]
error!(result, "No such file or directory");
#[cfg(target_os = "vxworks")]
error!(result, "no such file or directory");
#[cfg(windows)]
error!(result, 2); // ERROR_FILE_NOT_FOUND
}
@ -2352,8 +2354,10 @@ mod tests {
let result = fs::remove_file(filename);
#[cfg(unix)]
#[cfg(all(unix, not(target_os = "vxworks")))]
error!(result, "No such file or directory");
#[cfg(target_os = "vxworks")]
error!(result, "no such file or directory");
#[cfg(windows)]
error!(result, 2); // ERROR_FILE_NOT_FOUND
}
@ -2553,7 +2557,10 @@ mod tests {
check!(fs::set_permissions(filename, fs::Permissions::from_mode(0o1777)));
let metadata1 = check!(fs::metadata(filename));
#[cfg(all(unix, not(target_os = "vxworks")))]
assert_eq!(mask & metadata1.permissions().mode(), 0o1777);
#[cfg(target_os = "vxworks")]
assert_eq!(mask & metadata1.permissions().mode(), 0o0777);
}
#[test]

View file

@ -987,7 +987,6 @@ impl<'a> IoSliceMut<'a> {
/// #![feature(io_slice_advance)]
///
/// use std::io::IoSliceMut;
/// use std::mem;
/// use std::ops::Deref;
///
/// let mut buf1 = [1; 8];
@ -1000,7 +999,7 @@ impl<'a> IoSliceMut<'a> {
/// ][..];
///
/// // Mark 10 bytes as read.
/// bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 10);
/// bufs = IoSliceMut::advance(bufs, 10);
/// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
/// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
/// ```
@ -1090,20 +1089,19 @@ impl<'a> IoSlice<'a> {
/// #![feature(io_slice_advance)]
///
/// use std::io::IoSlice;
/// use std::mem;
/// use std::ops::Deref;
///
/// let mut buf1 = [1; 8];
/// let mut buf2 = [2; 16];
/// let mut buf3 = [3; 8];
/// let buf1 = [1; 8];
/// let buf2 = [2; 16];
/// let buf3 = [3; 8];
/// let mut bufs = &mut [
/// IoSlice::new(&mut buf1),
/// IoSlice::new(&mut buf2),
/// IoSlice::new(&mut buf3),
/// IoSlice::new(&buf1),
/// IoSlice::new(&buf2),
/// IoSlice::new(&buf3),
/// ][..];
///
/// // Mark 10 bytes as written.
/// bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 10);
/// bufs = IoSlice::advance(bufs, 10);
/// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
/// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
#[unstable(feature = "io_slice_advance", issue = "62726")]
@ -2415,7 +2413,6 @@ mod tests {
use crate::cmp;
use crate::io::prelude::*;
use crate::io::{self, IoSlice, IoSliceMut};
use crate::mem;
use crate::ops::Deref;
#[test]
@ -2731,26 +2728,26 @@ mod tests {
][..];
// Only in a single buffer..
bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 1);
bufs = IoSliceMut::advance(bufs, 1);
assert_eq!(bufs[0].deref(), [1; 7].as_ref());
assert_eq!(bufs[1].deref(), [2; 16].as_ref());
assert_eq!(bufs[2].deref(), [3; 8].as_ref());
// Removing a buffer, leaving others as is.
bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 7);
bufs = IoSliceMut::advance(bufs, 7);
assert_eq!(bufs[0].deref(), [2; 16].as_ref());
assert_eq!(bufs[1].deref(), [3; 8].as_ref());
// Removing a buffer and removing from the next buffer.
bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 18);
bufs = IoSliceMut::advance(bufs, 18);
assert_eq!(bufs[0].deref(), [3; 6].as_ref());
}
#[test]
fn io_slice_mut_advance_empty_slice() {
let mut empty_bufs = &mut [][..];
let empty_bufs = &mut [][..];
// Shouldn't panic.
IoSliceMut::advance(&mut empty_bufs, 1);
IoSliceMut::advance(empty_bufs, 1);
}
#[test]
@ -2759,48 +2756,48 @@ mod tests {
let mut bufs = &mut [IoSliceMut::new(&mut buf1)][..];
// Going beyond the total length should be ok.
bufs = IoSliceMut::advance(mem::replace(&mut bufs, &mut []), 9);
bufs = IoSliceMut::advance(bufs, 9);
assert!(bufs.is_empty());
}
#[test]
fn io_slice_advance() {
let mut buf1 = [1; 8];
let mut buf2 = [2; 16];
let mut buf3 = [3; 8];
let buf1 = [1; 8];
let buf2 = [2; 16];
let buf3 = [3; 8];
let mut bufs =
&mut [IoSlice::new(&mut buf1), IoSlice::new(&mut buf2), IoSlice::new(&mut buf3)][..];
&mut [IoSlice::new(&buf1), IoSlice::new(&buf2), IoSlice::new(&buf3)][..];
// Only in a single buffer..
bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 1);
bufs = IoSlice::advance(bufs, 1);
assert_eq!(bufs[0].deref(), [1; 7].as_ref());
assert_eq!(bufs[1].deref(), [2; 16].as_ref());
assert_eq!(bufs[2].deref(), [3; 8].as_ref());
// Removing a buffer, leaving others as is.
bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 7);
bufs = IoSlice::advance(bufs, 7);
assert_eq!(bufs[0].deref(), [2; 16].as_ref());
assert_eq!(bufs[1].deref(), [3; 8].as_ref());
// Removing a buffer and removing from the next buffer.
bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 18);
bufs = IoSlice::advance(bufs, 18);
assert_eq!(bufs[0].deref(), [3; 6].as_ref());
}
#[test]
fn io_slice_advance_empty_slice() {
let mut empty_bufs = &mut [][..];
let empty_bufs = &mut [][..];
// Shouldn't panic.
IoSlice::advance(&mut empty_bufs, 1);
IoSlice::advance(empty_bufs, 1);
}
#[test]
fn io_slice_advance_beyond_total_length() {
let mut buf1 = [1; 8];
let mut bufs = &mut [IoSlice::new(&mut buf1)][..];
let buf1 = [1; 8];
let mut bufs = &mut [IoSlice::new(&buf1)][..];
// Going beyond the total length should be ok.
bufs = IoSlice::advance(mem::replace(&mut bufs, &mut []), 9);
bufs = IoSlice::advance(bufs, 9);
assert!(bufs.is_empty());
}
}

View file

@ -44,19 +44,6 @@ impl<'a> Parser<'a> {
self.read_atomically(move |p| cb(p).filter(|_| p.is_eof()))
}
// Return result of first successful parser
fn read_or<T>(
&mut self,
parsers: &mut [Box<dyn FnMut(&mut Parser<'_>) -> Option<T> + 'static>],
) -> Option<T> {
for pf in parsers {
if let Some(r) = self.read_atomically(|p: &mut Parser<'_>| pf(p)) {
return Some(r);
}
}
None
}
// Apply 3 parsers sequentially
fn read_seq_3<A, B, C, PA, PB, PC>(&mut self, pa: PA, pb: PB, pc: PC) -> Option<(A, B, C)>
where
@ -235,9 +222,8 @@ impl<'a> Parser<'a> {
}
fn read_ip_addr(&mut self) -> Option<IpAddr> {
let ipv4_addr = |p: &mut Parser<'_>| p.read_ipv4_addr().map(IpAddr::V4);
let ipv6_addr = |p: &mut Parser<'_>| p.read_ipv6_addr().map(IpAddr::V6);
self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)])
self.read_ipv4_addr().map(IpAddr::V4)
.or_else(|| self.read_ipv6_addr().map(IpAddr::V6))
}
fn read_socket_addr_v4(&mut self) -> Option<SocketAddrV4> {
@ -268,9 +254,8 @@ impl<'a> Parser<'a> {
}
fn read_socket_addr(&mut self) -> Option<SocketAddr> {
let v4 = |p: &mut Parser<'_>| p.read_socket_addr_v4().map(SocketAddr::V4);
let v6 = |p: &mut Parser<'_>| p.read_socket_addr_v6().map(SocketAddr::V6);
self.read_or(&mut [Box::new(v4), Box::new(v6)])
self.read_socket_addr_v4().map(SocketAddr::V4)
.or_else(|| self.read_socket_addr_v6().map(SocketAddr::V6))
}
}

View file

@ -129,8 +129,9 @@ extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M,
}
extern "C" LLVMValueRef
LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, LLVMTypeRef Ty) {
return wrap(unwrap(M)->getOrInsertGlobal(Name, unwrap(Ty)));
LLVMRustGetOrInsertGlobal(LLVMModuleRef M, const char *Name, size_t NameLen, LLVMTypeRef Ty) {
StringRef NameRef(Name, NameLen);
return wrap(unwrap(M)->getOrInsertGlobal(NameRef, unwrap(Ty)));
}
extern "C" LLVMValueRef
@ -1287,11 +1288,12 @@ extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B,
}
extern "C" void LLVMRustSetComdat(LLVMModuleRef M, LLVMValueRef V,
const char *Name) {
const char *Name, size_t NameLen) {
Triple TargetTriple(unwrap(M)->getTargetTriple());
GlobalObject *GV = unwrap<GlobalObject>(V);
if (!TargetTriple.isOSBinFormatMachO()) {
GV->setComdat(unwrap(M)->getOrInsertComdat(Name));
StringRef NameRef(Name, NameLen);
GV->setComdat(unwrap(M)->getOrInsertComdat(NameRef));
}
}

View file

@ -0,0 +1,43 @@
// compile-flags: -C opt-level=0
#![crate_type = "lib"]
pub enum ApiError {}
#[allow(dead_code)]
pub struct TokioError {
b: bool,
}
pub enum Error {
Api {
source: ApiError,
},
Ethereum,
Tokio {
source: TokioError,
},
}
struct Api;
impl IntoError<Error> for Api
{
type Source = ApiError;
// CHECK-LABEL: @into_error
// CHECK: llvm.trap()
// Also check the next two instructions to make sure we do not match against `trap`
// elsewhere in the code.
// CHECK-NEXT: load
// CHECK-NEXT: ret
#[no_mangle]
fn into_error(self, error: Self::Source) -> Error {
Error::Api {
source: (|v| v)(error),
}
}
}
pub trait IntoError<E>
{
/// The underlying error
type Source;
/// Combine the information to produce the error
fn into_error(self, source: Self::Source) -> E;
}

View file

@ -0,0 +1,15 @@
// revisions: rpass cfail
enum A {
//[cfail]~^ ERROR 3:1: 3:7: recursive type `A` has infinite size [E0072]
B(C),
}
#[cfg(rpass)]
struct C(Box<A>);
#[cfg(cfail)]
struct C(A);
//[cfail]~^ ERROR 12:1: 12:13: recursive type `C` has infinite size [E0072]
fn main() {}

View file

@ -0,0 +1,4 @@
// This previously triggered an ICE.
pub(in crate::r#mod) fn main() {}
//~^ ERROR expected module, found unresolved item

View file

@ -0,0 +1,11 @@
error[E0577]: expected module, found unresolved item `crate::r#mod`
--> $DIR/issue-61732.rs:3:8
|
LL | pub(in crate::r#mod) fn main() {}
| ^^^^^^^^^^^^ not a module
error: Compilation failed, aborting rustdoc
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0577`.

View file

@ -0,0 +1,15 @@
#![crate_name = "foo"]
#![feature(doc_cfg)]
// @has 'foo/index.html'
// @!has '-' '//*[@class="stab portability"]' 'feature="sync" and'
// @has '-' '//*[@class="stab portability"]' 'feature="sync"'
#[doc(cfg(feature = "sync"))]
#[doc(cfg(feature = "sync"))]
pub struct Foo;
#[doc(cfg(feature = "sync"))]
pub mod bar {
#[doc(cfg(feature = "sync"))]
pub struct Bar;
}