Auto merge of #60969 - Centril:rollup-3j71mqj, r=Centril

Rollup of 6 pull requests

Successful merges:

 - #60590 (Test interaction of unions with non-zero/niche-filling optimization)
 - #60745 (Perform constant propagation into terminators)
 - #60895 (Enable thumbv7a-pc-windows-msvc target build end to end in rust/master)
 - #60908 (Fix lints handling in rustdoc)
 - #60960 (Stop using gensyms in HIR lowering)
 - #60962 (Fix data types indication)

Failed merges:

r? @ghost
This commit is contained in:
bors 2019-05-20 00:37:48 +00:00
commit 128b4c8035
23 changed files with 402 additions and 128 deletions

View File

@ -683,7 +683,7 @@ impl Step for RustdocUi {
target: self.target,
mode: "ui",
suite: "rustdoc-ui",
path: None,
path: Some("src/test/rustdoc-ui"),
compare_mode: None,
})
}

View File

@ -886,7 +886,7 @@ pub trait Pointer {
///
/// # Examples
///
/// Basic usage with `i32`:
/// Basic usage with `f64`:
///
/// ```
/// let x = 42.0; // 42.0 is '4.2e1' in scientific notation
@ -929,7 +929,7 @@ pub trait LowerExp {
///
/// # Examples
///
/// Basic usage with `f32`:
/// Basic usage with `f64`:
///
/// ```
/// let x = 42.0; // 42.0 is '4.2E1' in scientific notation

View File

@ -855,10 +855,6 @@ impl<'a> LoweringContext<'a> {
self.sess.diagnostic()
}
fn str_to_ident(&self, s: &'static str) -> Ident {
Ident::with_empty_ctxt(Symbol::gensym(s))
}
fn with_anonymous_lifetime_mode<R>(
&mut self,
anonymous_lifetime_mode: AnonymousLifetimeMode,
@ -4621,18 +4617,18 @@ impl<'a> LoweringContext<'a> {
);
head.span = desugared_span;
let iter = self.str_to_ident("iter");
let iter = Ident::with_empty_ctxt(sym::iter);
let next_ident = self.str_to_ident("__next");
let next_ident = Ident::with_empty_ctxt(sym::__next);
let (next_pat, next_pat_hid) = self.pat_ident_binding_mode(
desugared_span,
next_ident,
hir::BindingAnnotation::Mutable,
);
// `::std::option::Option::Some(val) => next = val`
// `::std::option::Option::Some(val) => __next = val`
let pat_arm = {
let val_ident = self.str_to_ident("val");
let val_ident = Ident::with_empty_ctxt(sym::val);
let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat_hid));
let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid));
@ -4771,17 +4767,13 @@ impl<'a> LoweringContext<'a> {
let unstable_span = self.sess.source_map().mark_span_with_reason(
CompilerDesugaringKind::QuestionMark,
e.span,
Some(vec![
Symbol::intern("try_trait")
].into()),
Some(vec![sym::try_trait].into()),
);
let try_span = self.sess.source_map().end_point(e.span);
let try_span = self.sess.source_map().mark_span_with_reason(
CompilerDesugaringKind::QuestionMark,
try_span,
Some(vec![
Symbol::intern("try_trait")
].into()),
Some(vec![sym::try_trait].into()),
);
// `Try::into_result(<expr>)`
@ -4802,7 +4794,8 @@ impl<'a> LoweringContext<'a> {
// `allow(unreachable_code)`
let allow = {
let allow_ident = Ident::with_empty_ctxt(sym::allow).with_span_pos(e.span);
let uc_ident = Ident::from_str("unreachable_code").with_span_pos(e.span);
let uc_ident = Ident::with_empty_ctxt(sym::unreachable_code)
.with_span_pos(e.span);
let uc_nested = attr::mk_nested_word_item(uc_ident);
attr::mk_list_item(e.span, allow_ident, vec![uc_nested])
};
@ -4812,7 +4805,7 @@ impl<'a> LoweringContext<'a> {
// `Ok(val) => #[allow(unreachable_code)] val,`
let ok_arm = {
let val_ident = self.str_to_ident("val");
let val_ident = Ident::with_empty_ctxt(sym::val);
let (val_pat, val_pat_nid) = self.pat_ident(e.span, val_ident);
let val_expr = P(self.expr_ident_with_attrs(
e.span,
@ -4828,7 +4821,7 @@ impl<'a> LoweringContext<'a> {
// `Err(err) => #[allow(unreachable_code)]
// return Try::from_error(From::from(err)),`
let err_arm = {
let err_ident = self.str_to_ident("err");
let err_ident = Ident::with_empty_ctxt(sym::err);
let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
let from_expr = {
let from_path = &[sym::convert, sym::From, sym::from];
@ -5552,7 +5545,7 @@ impl<'a> LoweringContext<'a> {
// match ::std::future::poll_with_tls_context(unsafe {
// ::std::pin::Pin::new_unchecked(&mut pinned)
// }) {
// ::std::task::Poll::Ready(x) => break x,
// ::std::task::Poll::Ready(result) => break result,
// ::std::task::Poll::Pending => {},
// }
// yield ();
@ -5580,12 +5573,12 @@ impl<'a> LoweringContext<'a> {
let gen_future_span = self.sess.source_map().mark_span_with_reason(
CompilerDesugaringKind::Await,
await_span,
Some(vec![Symbol::intern("gen_future")].into()),
Some(vec![sym::gen_future].into()),
);
// let mut pinned = <expr>;
let expr = P(self.lower_expr(expr));
let pinned_ident = self.str_to_ident("pinned");
let pinned_ident = Ident::with_empty_ctxt(sym::pinned);
let (pinned_pat, pinned_pat_hid) = self.pat_ident_binding_mode(
span,
pinned_ident,
@ -5621,11 +5614,11 @@ impl<'a> LoweringContext<'a> {
))
};
// `::std::task::Poll::Ready(x) => break x`
// `::std::task::Poll::Ready(result) => break result`
let loop_node_id = self.sess.next_node_id();
let loop_hir_id = self.lower_node_id(loop_node_id);
let ready_arm = {
let x_ident = self.str_to_ident("x");
let x_ident = Ident::with_empty_ctxt(sym::result);
let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident);
let x_expr = P(self.expr_ident(span, x_ident, x_pat_hid));
let ready_pat = self.pat_std_enum(

View File

@ -778,6 +778,9 @@ fn lint_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum)
let push = builder.levels.push(&krate.attrs);
builder.levels.register_id(hir::CRATE_HIR_ID);
for macro_def in &krate.exported_macros {
builder.levels.register_id(macro_def.hir_id);
}
intravisit::walk_crate(&mut builder, krate);
builder.levels.pop(push);

View File

@ -795,10 +795,10 @@ fn create_msvc_imps(
return
}
// The x86 ABI seems to require that leading underscores are added to symbol
// names, so we need an extra underscore on 32-bit. There's also a leading
// names, so we need an extra underscore on x86. There's also a leading
// '\x01' here which disables LLVM's symbol mangling (e.g., no extra
// underscores added in front).
let prefix = if cgcx.target_pointer_width == "32" {
let prefix = if cgcx.target_arch == "x86" {
"\x01__imp__"
} else {
"\x01__imp_"

View File

@ -248,6 +248,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
pub tm_factory: TargetMachineFactory<B>,
pub msvc_imps_needed: bool,
pub target_pointer_width: String,
pub target_arch: String,
pub debuginfo: config::DebugInfo,
// Number of cgus excluding the allocator/metadata modules
@ -1103,6 +1104,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
total_cgus,
msvc_imps_needed: msvc_imps_needed(tcx),
target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
target_arch: tcx.sess.target.target.arch.clone(),
debuginfo: tcx.sess.opts.debuginfo,
assembler_cmd,
};

View File

@ -546,6 +546,10 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
}
}
}
fn should_const_prop(&self) -> bool {
self.tcx.sess.opts.debugging_opts.mir_opt_level >= 2
}
}
fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@ -639,7 +643,7 @@ impl<'b, 'a, 'tcx> MutVisitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
assert!(self.places[local].is_none());
self.places[local] = Some(value);
if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
if self.should_const_prop() {
self.replace_with_const(rval, value, statement.source_info.span);
}
}
@ -656,75 +660,112 @@ impl<'b, 'a, 'tcx> MutVisitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
location: Location,
) {
self.super_terminator(terminator, location);
let source_info = terminator.source_info;;
if let TerminatorKind::Assert { expected, msg, cond, .. } = &terminator.kind {
if let Some(value) = self.eval_operand(&cond, source_info) {
trace!("assertion on {:?} should be {:?}", value, expected);
let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected));
if expected != self.ecx.read_scalar(value).unwrap() {
// poison all places this operand references so that further code
// doesn't use the invalid value
match cond {
Operand::Move(ref place) | Operand::Copy(ref place) => {
let mut place = place;
while let Place::Projection(ref proj) = *place {
place = &proj.base;
let source_info = terminator.source_info;
match &mut terminator.kind {
TerminatorKind::Assert { expected, msg, ref mut cond, .. } => {
if let Some(value) = self.eval_operand(&cond, source_info) {
trace!("assertion on {:?} should be {:?}", value, expected);
let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected));
let value_const = self.ecx.read_scalar(value).unwrap();
if expected != value_const {
// poison all places this operand references so that further code
// doesn't use the invalid value
match cond {
Operand::Move(ref place) | Operand::Copy(ref place) => {
let mut place = place;
while let Place::Projection(ref proj) = *place {
place = &proj.base;
}
if let Place::Base(PlaceBase::Local(local)) = *place {
self.places[local] = None;
}
},
Operand::Constant(_) => {}
}
let span = terminator.source_info.span;
let hir_id = self
.tcx
.hir()
.as_local_hir_id(self.source.def_id())
.expect("some part of a failing const eval must be local");
use rustc::mir::interpret::InterpError::*;
let msg = match msg {
Overflow(_) |
OverflowNeg |
DivisionByZero |
RemainderByZero => msg.description().to_owned(),
BoundsCheck { ref len, ref index } => {
let len = self
.eval_operand(len, source_info)
.expect("len must be const");
let len = match self.ecx.read_scalar(len) {
Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
bits, ..
})) => bits,
other => bug!("const len not primitive: {:?}", other),
};
let index = self
.eval_operand(index, source_info)
.expect("index must be const");
let index = match self.ecx.read_scalar(index) {
Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
bits, ..
})) => bits,
other => bug!("const index not primitive: {:?}", other),
};
format!(
"index out of bounds: \
the len is {} but the index is {}",
len,
index,
)
},
// Need proper const propagator for these
_ => return,
};
self.tcx.lint_hir(
::rustc::lint::builtin::CONST_ERR,
hir_id,
span,
&msg,
);
} else {
if self.should_const_prop() {
if let ScalarMaybeUndef::Scalar(scalar) = value_const {
*cond = self.operand_from_scalar(
scalar,
self.tcx.types.bool,
source_info.span,
);
}
if let Place::Base(PlaceBase::Local(local)) = *place {
self.places[local] = None;
}
},
Operand::Constant(_) => {}
}
}
let span = terminator.source_info.span;
let hir_id = self
.tcx
.hir()
.as_local_hir_id(self.source.def_id())
.expect("some part of a failing const eval must be local");
use rustc::mir::interpret::InterpError::*;
let msg = match msg {
Overflow(_) |
OverflowNeg |
DivisionByZero |
RemainderByZero => msg.description().to_owned(),
BoundsCheck { ref len, ref index } => {
let len = self
.eval_operand(len, source_info)
.expect("len must be const");
let len = match self.ecx.read_scalar(len) {
Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
bits, ..
})) => bits,
other => bug!("const len not primitive: {:?}", other),
};
let index = self
.eval_operand(index, source_info)
.expect("index must be const");
let index = match self.ecx.read_scalar(index) {
Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
bits, ..
})) => bits,
other => bug!("const index not primitive: {:?}", other),
};
format!(
"index out of bounds: \
the len is {} but the index is {}",
len,
index,
)
},
// Need proper const propagator for these
_ => return,
};
self.tcx.lint_hir(
::rustc::lint::builtin::CONST_ERR,
hir_id,
span,
&msg,
);
}
}
},
TerminatorKind::SwitchInt { ref mut discr, switch_ty, .. } => {
if self.should_const_prop() {
if let Some(value) = self.eval_operand(&discr, source_info) {
if let ScalarMaybeUndef::Scalar(scalar) =
self.ecx.read_scalar(value).unwrap() {
*discr = self.operand_from_scalar(scalar, switch_ty, source_info.span);
}
}
}
},
//none of these have Operands to const-propagate
TerminatorKind::Goto { .. } |
TerminatorKind::Resume |
TerminatorKind::Abort |
TerminatorKind::Return |
TerminatorKind::Unreachable |
TerminatorKind::Drop { .. } |
TerminatorKind::DropAndReplace { .. } |
TerminatorKind::Yield { .. } |
TerminatorKind::GeneratorDrop |
TerminatorKind::FalseEdges { .. } |
TerminatorKind::FalseUnwind { .. } => { }
//FIXME(wesleywiser) Call does have Operands that could be const-propagated
TerminatorKind::Call { .. } => { }
}
}
}

View File

@ -3408,6 +3408,7 @@ pub struct Span {
pub locol: usize,
pub hiline: usize,
pub hicol: usize,
pub original: syntax_pos::Span,
}
impl Span {
@ -3416,8 +3417,13 @@ impl Span {
filename: FileName::Anon(0),
loline: 0, locol: 0,
hiline: 0, hicol: 0,
original: syntax_pos::DUMMY_SP,
}
}
pub fn span(&self) -> syntax_pos::Span {
self.original
}
}
impl Clean<Span> for syntax_pos::Span {
@ -3436,6 +3442,7 @@ impl Clean<Span> for syntax_pos::Span {
locol: lo.col.to_usize(),
hiline: hi.line,
hicol: hi.col.to_usize(),
original: *self,
}
}
}

View File

@ -321,7 +321,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
if let Ok(res) = self.resolve(path_str, ns, &current_item, parent_node) {
res
} else {
resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
resolution_failure(cx, &item, path_str, &dox, link_range);
// This could just be a normal link or a broken link
// we could potentially check if something is
// "intra-doc-link-like" and warn in that case.
@ -332,7 +332,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
if let Ok(res) = self.resolve(path_str, ns, &current_item, parent_node) {
res
} else {
resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
resolution_failure(cx, &item, path_str, &dox, link_range);
// This could just be a normal link.
continue;
}
@ -357,7 +357,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
};
if candidates.is_empty() {
resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
resolution_failure(cx, &item, path_str, &dox, link_range);
// this could just be a normal link
continue;
}
@ -368,7 +368,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
} else {
ambiguity_error(
cx,
&item.attrs,
&item,
path_str,
&dox,
link_range,
@ -381,7 +381,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
if let Some(res) = macro_resolve(cx, path_str) {
(res, None)
} else {
resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
resolution_failure(cx, &item, path_str, &dox, link_range);
continue
}
}
@ -452,16 +452,24 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option<Res> {
/// line containing the failure as a note as well.
fn resolution_failure(
cx: &DocContext<'_>,
attrs: &Attributes,
item: &Item,
path_str: &str,
dox: &str,
link_range: Option<Range<usize>>,
) {
let hir_id = match cx.as_local_hir_id(item.def_id) {
Some(hir_id) => hir_id,
None => {
// If non-local, no need to check anything.
return;
}
};
let attrs = &item.attrs;
let sp = span_of_attrs(attrs);
let mut diag = cx.tcx.struct_span_lint_hir(
lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
hir::CRATE_HIR_ID,
hir_id,
sp,
&format!("`[{}]` cannot be resolved, ignoring it...", path_str),
);
@ -495,12 +503,20 @@ fn resolution_failure(
fn ambiguity_error(
cx: &DocContext<'_>,
attrs: &Attributes,
item: &Item,
path_str: &str,
dox: &str,
link_range: Option<Range<usize>>,
candidates: PerNS<Option<Res>>,
) {
let hir_id = match cx.as_local_hir_id(item.def_id) {
Some(hir_id) => hir_id,
None => {
// If non-local, no need to check anything.
return;
}
};
let attrs = &item.attrs;
let sp = span_of_attrs(attrs);
let mut msg = format!("`{}` is ", path_str);
@ -532,7 +548,7 @@ fn ambiguity_error(
let mut diag = cx.tcx.struct_span_lint_hir(
lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
hir::CRATE_HIR_ID,
hir_id,
sp,
&msg,
);

View File

@ -1,7 +1,6 @@
//! Contains information about "passes", used to modify crate information during the documentation
//! process.
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::lint as lint;
use rustc::middle::privacy::AccessLevels;
@ -314,10 +313,13 @@ pub fn look_for_tests<'tcx>(
item: &Item,
check_missing_code: bool,
) {
if cx.as_local_hir_id(item.def_id).is_none() {
// If non-local, no need to check anything.
return;
}
let hir_id = match cx.as_local_hir_id(item.def_id) {
Some(hir_id) => hir_id,
None => {
// If non-local, no need to check anything.
return;
}
};
struct Tests {
found_tests: usize,
@ -336,10 +338,11 @@ pub fn look_for_tests<'tcx>(
find_testable_code(&dox, &mut tests, ErrorCodes::No);
if check_missing_code == true && tests.found_tests == 0 {
let sp = span_of_attrs(&item.attrs).substitute_dummy(item.source.span());
let mut diag = cx.tcx.struct_span_lint_hir(
lint::builtin::MISSING_DOC_CODE_EXAMPLES,
hir::CRATE_HIR_ID,
span_of_attrs(&item.attrs),
hir_id,
sp,
"Missing code example in this documentation");
diag.emit();
} else if check_missing_code == false &&
@ -347,7 +350,7 @@ pub fn look_for_tests<'tcx>(
!cx.renderinfo.borrow().access_levels.is_doc_reachable(item.def_id) {
let mut diag = cx.tcx.struct_span_lint_hir(
lint::builtin::PRIVATE_DOC_TESTS,
hir::CRATE_HIR_ID,
hir_id,
span_of_attrs(&item.attrs),
"Documentation test in private item");
diag.emit();

View File

@ -229,6 +229,7 @@ symbols! {
eh_personality,
eh_unwind_resume,
enable,
err,
Err,
except,
exclusive_range_pattern,
@ -260,6 +261,7 @@ symbols! {
fundamental,
future,
Future,
gen_future,
generators,
generic_associated_types,
generic_param_attrs,
@ -361,6 +363,7 @@ symbols! {
never,
never_type,
next,
__next,
nll,
no_builtins,
no_core,
@ -406,6 +409,7 @@ symbols! {
Pending,
pin,
Pin,
pinned,
platform_intrinsics,
plugin,
plugin_registrar,
@ -569,6 +573,7 @@ symbols! {
trivial_bounds,
Try,
try_blocks,
try_trait,
tuple_indexing,
ty,
type_alias_enum_variants,
@ -587,6 +592,7 @@ symbols! {
uniform_paths,
universal_impl_trait,
unmarked_api,
unreachable_code,
unrestricted_attribute_tokens,
unsafe_destructor_blind_to_params,
unsafe_no_drop_flag,
@ -601,6 +607,7 @@ symbols! {
use_nested_groups,
usize,
v1,
val,
vis,
visible_private_types,
volatile,

View File

@ -37,12 +37,13 @@ extern crate libc;
use term;
// FIXME(#54291): rustc and/or LLVM don't yet support building with panic-unwind
// on aarch64-pc-windows-msvc, so we don't link libtest against
// libunwind (for the time being), even though it means that
// libtest won't be fully functional on this platform.
// on aarch64-pc-windows-msvc, or thumbv7a-pc-windows-msvc
// so we don't link libtest against libunwind (for the time being)
// even though it means that libtest won't be fully functional on
// these platforms.
//
// See also: https://github.com/rust-lang/rust/issues/54190#issuecomment-422904437
#[cfg(not(all(windows, target_arch = "aarch64")))]
#[cfg(not(all(windows, any(target_arch = "aarch64", target_arch = "arm"))))]
extern crate panic_unwind;
pub use self::ColorConfig::*;

View File

@ -23,7 +23,7 @@ fn main() {
// bb0: {
// ...
// _5 = const true;
// assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb1;
// assert(const true, "index out of bounds: the len is move _4 but the index is _3") -> bb1;
// }
// bb1: {
// _1 = _2[_3];

View File

@ -16,6 +16,6 @@ fn main() {
// bb0: {
// ...
// _2 = (const 2u32, const false);
// assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1;
// assert(!const false, "attempt to add with overflow") -> bb1;
// }
// END rustc.main.ConstProp.after.mir

View File

@ -0,0 +1,38 @@
#[inline(never)]
fn foo(_: i32) { }
fn main() {
match 1 {
1 => foo(0),
_ => foo(-1),
}
}
// END RUST SOURCE
// START rustc.main.ConstProp.before.mir
// bb0: {
// ...
// _1 = const 1i32;
// switchInt(_1) -> [1i32: bb1, otherwise: bb2];
// }
// END rustc.main.ConstProp.before.mir
// START rustc.main.ConstProp.after.mir
// bb0: {
// ...
// switchInt(const 1i32) -> [1i32: bb1, otherwise: bb2];
// }
// END rustc.main.ConstProp.after.mir
// START rustc.main.SimplifyBranches-after-const-prop.before.mir
// bb0: {
// ...
// _1 = const 1i32;
// switchInt(const 1i32) -> [1i32: bb1, otherwise: bb2];
// }
// END rustc.main.SimplifyBranches-after-const-prop.before.mir
// START rustc.main.SimplifyBranches-after-const-prop.after.mir
// bb0: {
// ...
// _1 = const 1i32;
// goto -> bb1;
// }
// END rustc.main.SimplifyBranches-after-const-prop.after.mir

View File

@ -5,15 +5,15 @@ fn main() {
}
// END RUST SOURCE
// START rustc.main.SimplifyBranches-after-copy-prop.before.mir
// START rustc.main.SimplifyBranches-after-const-prop.before.mir
// bb0: {
// ...
// switchInt(const false) -> [false: bb3, otherwise: bb1];
// }
// END rustc.main.SimplifyBranches-after-copy-prop.before.mir
// START rustc.main.SimplifyBranches-after-copy-prop.after.mir
// END rustc.main.SimplifyBranches-after-const-prop.before.mir
// START rustc.main.SimplifyBranches-after-const-prop.after.mir
// bb0: {
// ...
// goto -> bb3;
// }
// END rustc.main.SimplifyBranches-after-copy-prop.after.mir
// END rustc.main.SimplifyBranches-after-const-prop.after.mir

View File

@ -0,0 +1,51 @@
// run-pass
#![allow(dead_code)]
// Tests that unions aren't subject to unsafe non-zero/niche-filling optimizations.
//
// For example, if a union `U` can contain both a `&T` and a `*const T`, there's definitely no
// bit-value that an `Option<U>` could reuse as `None`; this test makes sure that isn't done.
//
// Secondly, this tests the status quo (not a guarantee; subject to change!) to not apply such
// optimizations to types containing unions even if they're theoretically possible. (discussion:
// https://github.com/rust-lang/rust/issues/36394)
//
// Notably this nails down part of the behavior that `MaybeUninit` assumes: that a
// `Option<MaybeUninit<&u8>>` does not take advantage of non-zero optimization, and thus is a safe
// construct.
use std::mem::{size_of, transmute};
union U1<A: Copy> {
a: A,
}
union U2<A: Copy, B: Copy> {
a: A,
b: B,
}
// Option<E> uses a value other than 0 and 1 as None
#[derive(Clone,Copy)]
enum E {
A = 0,
B = 1,
}
fn main() {
// Unions do not participate in niche-filling/non-zero optimization...
assert!(size_of::<Option<U2<&u8, u8>>>() > size_of::<U2<&u8, u8>>());
assert!(size_of::<Option<U2<&u8, ()>>>() > size_of::<U2<&u8, ()>>());
assert!(size_of::<Option<U2<u8, E>>>() > size_of::<U2<u8, E>>());
// ...even when theoretically possible:
assert!(size_of::<Option<U1<&u8>>>() > size_of::<U1<&u8>>());
assert!(size_of::<Option<U2<&u8, &u8>>>() > size_of::<U2<&u8, &u8>>());
// The unused bits of the () variant can have any value.
let zeroed: U2<&u8, ()> = unsafe { transmute(std::ptr::null::<u8>()) };
if let None = Some(zeroed) {
panic!()
}
}

View File

@ -1,6 +1,4 @@
//~ ERROR Missing code example in this documentation
#![deny(missing_doc_code_examples)]
#![deny(missing_doc_code_examples)] //~ ERROR Missing code example in this documentation
/// Some docs.
//~^ ERROR Missing code example in this documentation

View File

@ -1,25 +1,35 @@
error: Missing code example in this documentation
--> $DIR/doc-without-codeblock.rs:1:1
|
LL | / #![deny(missing_doc_code_examples)]
LL | |
LL | | /// Some docs.
LL | |
... |
LL | | pub fn bar() {}
LL | | }
| |_^
|
note: lint level defined here
--> $DIR/doc-without-codeblock.rs:3:9
--> $DIR/doc-without-codeblock.rs:1:9
|
LL | #![deny(missing_doc_code_examples)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: Missing code example in this documentation
--> $DIR/doc-without-codeblock.rs:5:1
--> $DIR/doc-without-codeblock.rs:3:1
|
LL | /// Some docs.
| ^^^^^^^^^^^^^^
error: Missing code example in this documentation
--> $DIR/doc-without-codeblock.rs:9:1
--> $DIR/doc-without-codeblock.rs:7:1
|
LL | /// And then, the princess died.
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: Missing code example in this documentation
--> $DIR/doc-without-codeblock.rs:12:5
--> $DIR/doc-without-codeblock.rs:10:5
|
LL | /// Or maybe not because she saved herself!
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -0,0 +1,40 @@
#![deny(missing_docs)]
#![deny(missing_doc_code_examples)]
//! crate level doc
//! ```
//! println!("hello"):
//! ```
/// doc
///
/// ```
/// println!("hello");
/// ```
fn test() {
}
#[allow(missing_docs)]
mod module1 { //~ ERROR
}
#[allow(missing_doc_code_examples)]
/// doc
mod module2 {
/// doc
pub fn test() {}
}
/// doc
///
/// ```
/// println!("hello");
/// ```
pub mod module3 {
/// doc
//~^ ERROR
pub fn test() {}
}

View File

@ -0,0 +1,21 @@
error: Missing code example in this documentation
--> $DIR/lint-missing-doc-code-example.rs:19:1
|
LL | / mod module1 {
LL | | }
| |_^
|
note: lint level defined here
--> $DIR/lint-missing-doc-code-example.rs:2:9
|
LL | #![deny(missing_doc_code_examples)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: Missing code example in this documentation
--> $DIR/lint-missing-doc-code-example.rs:37:3
|
LL | /// doc
| ^^^^^^^
error: aborting due to 2 previous errors

View File

@ -57,6 +57,15 @@ pub enum Enum4<A, B, C, D> {
Four(D)
}
pub union Union1<A: Copy> {
a: A,
}
pub union Union2<A: Copy, B: Copy> {
a: A,
b: B,
}
#[start]
fn start(_: isize, _: *const *const u8) -> isize {
let _x: MyOption<NonZeroU32> = Default::default();
@ -69,5 +78,13 @@ fn start(_: isize, _: *const *const u8) -> isize {
let _e: Enum4<(), char, (), ()> = Enum4::One(());
let _f: Enum4<(), (), bool, ()> = Enum4::One(());
let _g: Enum4<(), (), (), MyOption<u8>> = Enum4::One(());
// Unions do not currently participate in niche filling.
let _h: MyOption<Union2<NonZeroU32, u32>> = Default::default();
// ...even when theoretically possible.
let _i: MyOption<Union1<NonZeroU32>> = Default::default();
let _j: MyOption<Union2<NonZeroU32, NonZeroU32>> = Default::default();
0
}

View File

@ -14,6 +14,21 @@ print-type-size field `.post`: 2 bytes
print-type-size field `.pre`: 1 bytes
print-type-size variant `None`: 0 bytes
print-type-size end padding: 1 bytes
print-type-size type: `MyOption<Union1<std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
print-type-size discriminant: 4 bytes
print-type-size variant `Some`: 4 bytes
print-type-size field `.0`: 4 bytes
print-type-size variant `None`: 0 bytes
print-type-size type: `MyOption<Union2<std::num::NonZeroU32, std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
print-type-size discriminant: 4 bytes
print-type-size variant `Some`: 4 bytes
print-type-size field `.0`: 4 bytes
print-type-size variant `None`: 0 bytes
print-type-size type: `MyOption<Union2<std::num::NonZeroU32, u32>>`: 8 bytes, alignment: 4 bytes
print-type-size discriminant: 4 bytes
print-type-size variant `Some`: 4 bytes
print-type-size field `.0`: 4 bytes
print-type-size variant `None`: 0 bytes
print-type-size type: `NestedNonZero`: 8 bytes, alignment: 4 bytes
print-type-size field `.val`: 4 bytes
print-type-size field `.post`: 2 bytes
@ -36,6 +51,17 @@ print-type-size type: `MyOption<std::num::NonZeroU32>`: 4 bytes, alignment: 4 by
print-type-size variant `Some`: 4 bytes
print-type-size field `.0`: 4 bytes
print-type-size variant `None`: 0 bytes
print-type-size type: `Union1<std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes
print-type-size variant `Union1`: 4 bytes
print-type-size field `.a`: 4 bytes
print-type-size type: `Union2<std::num::NonZeroU32, std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes
print-type-size variant `Union2`: 4 bytes
print-type-size field `.a`: 4 bytes
print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes
print-type-size type: `Union2<std::num::NonZeroU32, u32>`: 4 bytes, alignment: 4 bytes
print-type-size variant `Union2`: 4 bytes
print-type-size field `.a`: 4 bytes
print-type-size field `.b`: 4 bytes, offset: 0 bytes, alignment: 4 bytes
print-type-size type: `std::num::NonZeroU32`: 4 bytes, alignment: 4 bytes
print-type-size field `.0`: 4 bytes
print-type-size type: `Enum4<(), (), (), MyOption<u8>>`: 2 bytes, alignment: 1 bytes