mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
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:
commit
128b4c8035
@ -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,
|
||||
})
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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_"
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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 { .. } => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -321,7 +321,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
|
||||
if let Ok(res) = self.resolve(path_str, ns, ¤t_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, ¤t_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,
|
||||
);
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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::*;
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
38
src/test/mir-opt/const_prop/switch_int.rs
Normal file
38
src/test/mir-opt/const_prop/switch_int.rs
Normal 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
|
@ -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
|
||||
|
51
src/test/run-pass/union/union-nonzero.rs
Normal file
51
src/test/run-pass/union/union-nonzero.rs
Normal 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!()
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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!
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
40
src/test/rustdoc-ui/lint-missing-doc-code-example.rs
Normal file
40
src/test/rustdoc-ui/lint-missing-doc-code-example.rs
Normal 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() {}
|
||||
}
|
21
src/test/rustdoc-ui/lint-missing-doc-code-example.stderr
Normal file
21
src/test/rustdoc-ui/lint-missing-doc-code-example.stderr
Normal 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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user