fast_finish: true
include:
# Images used in testing PR and try-build should be run first.
- - env: IMAGE=x86_64-gnu-llvm-3.9 RUST_BACKTRACE=1
+ - env: IMAGE=x86_64-gnu-llvm-5.0 RUST_BACKTRACE=1
if: type = pull_request OR branch = auto
- env: IMAGE=dist-x86_64-linux DEPLOY=1
builder.copy_to_folder(&src, &target_bin_dir);
}
+ // Warn windows-gnu users that the bundled GCC cannot compile C files
+ builder.create(
+ &target_bin_dir.join("GCC-WARNING.txt"),
+ "gcc.exe contained in this folder cannot be used for compiling C files - it is only\
+ used as a linker. In order to be able to compile projects containing C code use\
+ the GCC provided by MinGW or Cygwin."
+ );
+
//Copy platform libs to platform-specific lib directory
let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib");
fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
let version = output(cmd.arg("--version"));
let mut parts = version.split('.').take(2)
.filter_map(|s| s.parse::<u32>().ok());
- if let (Some(major), Some(minor)) = (parts.next(), parts.next()) {
- if major > 3 || (major == 3 && minor >= 9) {
+ if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) {
+ if major >= 5 {
return
}
}
- panic!("\n\nbad LLVM version: {}, need >=3.9\n\n", version)
+ panic!("\n\nbad LLVM version: {}, need >=5.0\n\n", version)
}
fn configure_cmake(builder: &Builder,
+++ /dev/null
-FROM ubuntu:16.04
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
- g++ \
- make \
- file \
- curl \
- ca-certificates \
- python2.7 \
- git \
- cmake \
- sudo \
- gdb \
- llvm-3.9-tools \
- libedit-dev \
- zlib1g-dev \
- xz-utils
-
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
-
-# using llvm-link-shared due to libffi issues -- see #34486
-ENV RUST_CONFIGURE_ARGS \
- --build=x86_64-unknown-linux-gnu \
- --llvm-root=/usr/lib/llvm-3.9 \
- --enable-llvm-link-shared
-ENV RUST_CHECK_TARGET check
--- /dev/null
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ g++ \
+ make \
+ file \
+ curl \
+ ca-certificates \
+ python2.7 \
+ git \
+ cmake \
+ sudo \
+ gdb \
+ llvm-5.0-tools \
+ libedit-dev \
+ zlib1g-dev \
+ xz-utils
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+# using llvm-link-shared due to libffi issues -- see #34486
+ENV RUST_CONFIGURE_ARGS \
+ --build=x86_64-unknown-linux-gnu \
+ --llvm-root=/usr/lib/llvm-5.0 \
+ --enable-llvm-link-shared
+ENV RUST_CHECK_TARGET check
/// use specific allocators with looser requirements.)
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[cfg_attr(not(stage0), lang = "alloc_layout")]
pub struct Layout {
// size of the requested block of memory, measured in bytes.
size_: usize,
Type(Ty),
}
+impl GenericArg {
+ pub fn span(&self) -> Span {
+ match self {
+ GenericArg::Lifetime(l) => l.span,
+ GenericArg::Type(t) => t.span,
+ }
+ }
+}
+
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct GenericArgs {
/// The generic arguments for this path segment.
// Ensure that we never exceed the `--cap-lints` argument.
level = cmp::min(level, self.lint_cap);
+ if let Some(driver_level) = sess.driver_lint_caps.get(&LintId::of(lint)) {
+ // Ensure that we never exceed driver level.
+ level = cmp::min(*driver_level, level);
+ }
+
return (level, src)
}
fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt,
id: ast::NodeId,
attrs: &[ast::Attribute]) -> bool {
- if attr::contains_name(attrs, "lang") || attr::contains_name(attrs, "panic_implementation") {
+ if attr::contains_name(attrs, "lang") {
+ return true;
+ }
+
+ // (To be) stable attribute for #[lang = "panic_impl"]
+ if attr::contains_name(attrs, "panic_implementation") {
+ return true;
+ }
+
+ // (To be) stable attribute for #[lang = "oom"]
+ if attr::contains_name(attrs, "alloc_error_handler") {
return true;
}
}
} else if attribute.check_name("panic_implementation") {
return Some((Symbol::intern("panic_impl"), attribute.span))
+ } else if attribute.check_name("alloc_error_handler") {
+ return Some((Symbol::intern("oom"), attribute.span))
}
}
BoxFreeFnLangItem, "box_free", box_free_fn;
DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn;
OomLangItem, "oom", oom;
+ AllocLayoutLangItem, "alloc_layout", alloc_layout;
StartFnLangItem, "start", start_fn;
if lang_items::$item == lang_items::PanicImplLangItem {
tcx.sess.err(&format!("`#[panic_implementation]` function required, \
but not found"));
+ } else if lang_items::$item == lang_items::OomLangItem {
+ tcx.sess.err(&format!("`#[alloc_error_handler]` function required, \
+ but not found"));
} else {
tcx.sess.err(&format!("language item required, but not found: `{}`",
stringify!($name)));
use session::search_paths::PathKind;
use session::config::{OutputType};
use ty::tls;
-use util::nodemap::{FxHashSet};
+use util::nodemap::{FxHashMap, FxHashSet};
use util::common::{duration_to_secs_str, ErrorReported};
use util::common::ProfileQueriesMsg;
/// Metadata about the allocators for the current crate being compiled
pub has_global_allocator: Once<bool>,
+
+ /// Cap lint level specified by a driver specifically.
+ pub driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
}
pub struct PerfStats {
(*GLOBAL_JOBSERVER).clone()
},
has_global_allocator: Once::new(),
+ driver_lint_caps: FxHashMap(),
};
sess
let mut abi = Abi::Aggregate { sized: true };
if tag.value.size(dl) == size {
abi = Abi::Scalar(tag.clone());
- } else if !tag.is_bool() {
- // HACK(nox): Blindly using ScalarPair for all tagged enums
- // where applicable leads to Option<u8> being handled as {i1, i8},
- // which later confuses SROA and some loop optimisations,
- // ultimately leading to the repeat-trusted-len test
- // failing. We make the trade-off of using ScalarPair only
- // for types where the tag isn't a boolean.
+ } else {
+ // Try to use a ScalarPair for all tagged enums.
let mut common_prim = None;
for (field_layouts, layout_variant) in variants.iter().zip(&layout_variants) {
let offsets = match layout_variant.fields {
PassMode::Ignore => continue,
PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx),
PassMode::Pair(..) => {
- llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0));
- llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1));
+ llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true));
+ llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true));
continue;
}
PassMode::Cast(cast) => cast.llvm_type(cx),
layout::Int(..) if !scalar.is_bool() => {
let range = scalar.valid_range_exclusive(bx.cx);
if range.start != range.end {
- // FIXME(nox): This causes very weird type errors about
- // SHL operators in constants in stage 2 with LLVM 3.9.
- if unsafe { llvm::LLVMRustVersionMajor() >= 4 } {
- bx.range_metadata(callsite, range);
- }
+ bx.range_metadata(callsite, range);
}
}
_ => {}
}
let (lldata, llextra) = result.unwrap();
// HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
- (bx.bitcast(lldata, dst_layout.scalar_pair_element_llvm_type(bx.cx, 0)),
- bx.bitcast(llextra, dst_layout.scalar_pair_element_llvm_type(bx.cx, 1)))
+ (bx.bitcast(lldata, dst_layout.scalar_pair_element_llvm_type(bx.cx, 0, true)),
+ bx.bitcast(llextra, dst_layout.scalar_pair_element_llvm_type(bx.cx, 1, true)))
}
_ => bug!("unsize_thin_ptr: called on bad types"),
}
pub fn to_immediate(bx: &Builder, val: ValueRef, layout: layout::TyLayout) -> ValueRef {
if let layout::Abi::Scalar(ref scalar) = layout.abi {
- if scalar.is_bool() {
- return bx.trunc(val, Type::i1(bx.cx));
- }
+ return to_immediate_scalar(bx, val, scalar);
+ }
+ val
+}
+
+pub fn to_immediate_scalar(bx: &Builder, val: ValueRef, scalar: &layout::Scalar) -> ValueRef {
+ if scalar.is_bool() {
+ return bx.trunc(val, Type::i1(bx.cx));
}
val
}
use common::{CodegenCx, Funclet};
use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext};
use monomorphize::Instance;
-use abi::{ArgAttribute, ArgTypeExt, FnType, FnTypeExt, PassMode};
+use abi::{ArgTypeExt, FnType, FnTypeExt, PassMode};
use type_::Type;
use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span};
None
};
- let deref_op = unsafe {
- [llvm::LLVMRustDIBuilderCreateOpDeref()]
- };
-
mir.args_iter().enumerate().map(|(arg_index, local)| {
let arg_decl = &mir.local_decls[local];
if arg_index > 0 || mir.upvar_decls.is_empty() {
// The Rust ABI passes indirect variables using a pointer and a manual copy, so we
// need to insert a deref here, but the C ABI uses a pointer and a copy using the
- // byval attribute, for which LLVM does the deref itself, so we must not add it.
- // Starting with D31439 in LLVM 5, it *always* does the deref itself.
- let mut variable_access = VariableAccess::DirectVariable {
+ // byval attribute, for which LLVM always does the deref itself,
+ // so we must not add it.
+ let variable_access = VariableAccess::DirectVariable {
alloca: place.llval
};
- if unsafe { llvm::LLVMRustVersionMajor() < 5 } {
- if let PassMode::Indirect(ref attrs) = arg.mode {
- if !attrs.contains(ArgAttribute::ByVal) {
- variable_access = VariableAccess::IndirectVariable {
- alloca: place.llval,
- address_operations: &deref_op,
- };
- }
- }
- }
declare_local(
bx,
use rustc_data_structures::sync::Lrc;
use base;
-use common::{self, CodegenCx, C_null, C_undef, C_usize};
+use common::{CodegenCx, C_null, C_undef, C_usize};
use builder::{Builder, MemFlags};
use value::Value;
use type_of::LayoutLlvmExt;
bx.cx,
a,
a_scalar,
- layout.scalar_pair_element_llvm_type(bx.cx, 0),
+ layout.scalar_pair_element_llvm_type(bx.cx, 0, true),
);
let b_llval = scalar_to_llvm(
bx.cx,
b,
b_scalar,
- layout.scalar_pair_element_llvm_type(bx.cx, 1),
+ layout.scalar_pair_element_llvm_type(bx.cx, 1, true),
);
OperandValue::Pair(a_llval, b_llval)
},
self, llty);
// Reconstruct the immediate aggregate.
let mut llpair = C_undef(llty);
- llpair = bx.insert_value(llpair, a, 0);
- llpair = bx.insert_value(llpair, b, 1);
+ llpair = bx.insert_value(llpair, base::from_immediate(bx, a), 0);
+ llpair = bx.insert_value(llpair, base::from_immediate(bx, b), 1);
llpair
} else {
self.immediate()
llval: ValueRef,
layout: TyLayout<'tcx>)
-> OperandRef<'tcx> {
- let val = if layout.is_llvm_scalar_pair() {
+ let val = if let layout::Abi::ScalarPair(ref a, ref b) = layout.abi {
debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}",
llval, layout);
// Deconstruct the immediate aggregate.
- OperandValue::Pair(bx.extract_value(llval, 0),
- bx.extract_value(llval, 1))
+ let a_llval = base::to_immediate_scalar(bx, bx.extract_value(llval, 0), a);
+ let b_llval = base::to_immediate_scalar(bx, bx.extract_value(llval, 1), b);
+ OperandValue::Pair(a_llval, b_llval)
} else {
OperandValue::Immediate(llval)
};
*llval = bx.bitcast(*llval, field.immediate_llvm_type(bx.cx));
}
OperandValue::Pair(ref mut a, ref mut b) => {
- *a = bx.bitcast(*a, field.scalar_pair_element_llvm_type(bx.cx, 0));
- *b = bx.bitcast(*b, field.scalar_pair_element_llvm_type(bx.cx, 1));
+ *a = bx.bitcast(*a, field.scalar_pair_element_llvm_type(bx.cx, 0, true));
+ *b = bx.bitcast(*b, field.scalar_pair_element_llvm_type(bx.cx, 1, true));
}
OperandValue::Ref(..) => bug!()
}
}
OperandValue::Pair(a, b) => {
for (i, &x) in [a, b].iter().enumerate() {
- let mut llptr = bx.struct_gep(dest.llval, i as u64);
- // Make sure to always store i1 as i8.
- if common::val_ty(x) == Type::i1(bx.cx) {
- llptr = bx.pointercast(llptr, Type::i8p(bx.cx));
- }
+ let llptr = bx.struct_gep(dest.llval, i as u64);
let val = base::from_immediate(bx, x);
bx.store_with_flags(val, llptr, dest.align, flags);
}
OperandValue::Immediate(base::to_immediate(bx, llval, self.layout))
} else if let layout::Abi::ScalarPair(ref a, ref b) = self.layout.abi {
let load = |i, scalar: &layout::Scalar| {
- let mut llptr = bx.struct_gep(self.llval, i as u64);
- // Make sure to always load i1 as i8.
- if scalar.is_bool() {
- llptr = bx.pointercast(llptr, Type::i8p(bx.cx));
- }
+ let llptr = bx.struct_gep(self.llval, i as u64);
let load = bx.load(llptr, self.align);
scalar_load_metadata(load, scalar);
if scalar.is_bool() {
// HACK(eddyb) have to bitcast pointers
// until LLVM removes pointee types.
let lldata = bx.pointercast(lldata,
- cast.scalar_pair_element_llvm_type(bx.cx, 0));
+ cast.scalar_pair_element_llvm_type(bx.cx, 0, true));
OperandValue::Pair(lldata, llextra)
}
OperandValue::Immediate(lldata) => {
if let OperandValue::Pair(data_ptr, meta) = operand.val {
if cast.is_llvm_scalar_pair() {
let data_cast = bx.pointercast(data_ptr,
- cast.scalar_pair_element_llvm_type(bx.cx, 0));
+ cast.scalar_pair_element_llvm_type(bx.cx, 0, true));
OperandValue::Pair(data_cast, meta)
} else { // cast to thin-ptr
// Cast of fat-ptr to thin-ptr is an extraction of data-ptr and
}
layout::Abi::ScalarPair(..) => {
return Type::struct_(cx, &[
- layout.scalar_pair_element_llvm_type(cx, 0),
- layout.scalar_pair_element_llvm_type(cx, 1),
+ layout.scalar_pair_element_llvm_type(cx, 0, false),
+ layout.scalar_pair_element_llvm_type(cx, 1, false),
], false);
}
layout::Abi::Uninhabited |
fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>,
scalar: &layout::Scalar, offset: Size) -> Type;
fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>,
- index: usize) -> Type;
+ index: usize, immediate: bool) -> Type;
fn llvm_field_index(&self, index: usize) -> u64;
fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size)
-> Option<PointeeInfo>;
}
fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>,
- index: usize) -> Type {
+ index: usize, immediate: bool) -> Type {
// HACK(eddyb) special-case fat pointers until LLVM removes
// pointee types, to avoid bitcasting every `OperandRef::deref`.
match self.ty.sty {
}
ty::TyAdt(def, _) if def.is_box() => {
let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty());
- return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index);
+ return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate);
}
_ => {}
}
};
let scalar = [a, b][index];
- // Make sure to return the same type `immediate_llvm_type` would,
- // to avoid dealing with two types and the associated conversions.
- // This means that `(bool, bool)` is represented as `{i1, i1}`,
- // both in memory and as an immediate, while `bool` is typically
- // `i8` in memory and only `i1` when immediate. While we need to
- // load/store `bool` as `i8` to avoid crippling LLVM optimizations,
- // `i1` in a LLVM aggregate is valid and mostly equivalent to `i8`.
- if scalar.is_bool() {
+ // Make sure to return the same type `immediate_llvm_type` would when
+ // dealing with an immediate pair. This means that `(bool, bool)` is
+ // effectively represented as `{i8, i8}` in memory and two `i1`s as an
+ // immediate, just like `bool` is typically `i8` in memory and only `i1`
+ // when immediate. We need to load/store `bool` as `i8` to avoid
+ // crippling LLVM optimizations or triggering other LLVM bugs with `i1`.
+ if immediate && scalar.is_bool() {
return Type::i1(cx);
}
// Temporarily have stack size set to 16MB to deal with nom-using crates failing
const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB
- #[cfg(unix)]
+ #[cfg(all(unix,not(target_os = "haiku")))]
let spawn_thread = unsafe {
// Fetch the current resource limits
let mut rlim = libc::rlimit {
#[cfg(windows)]
let spawn_thread = false;
+ #[cfg(target_os = "haiku")]
+ let spawn_thread = unsafe {
+ // Haiku does not have setrlimit implemented for the stack size.
+ // By default it does have the 16 MB stack limit, but we check this in
+ // case the minimum STACK_SIZE changes or Haiku's defaults change.
+ let mut rlim = libc::rlimit {
+ rlim_cur: 0,
+ rlim_max: 0,
+ };
+ if libc::getrlimit(libc::RLIMIT_STACK, &mut rlim) != 0 {
+ let err = io::Error::last_os_error();
+ error!("in_rustc_thread: error calling getrlimit: {}", err);
+ true
+ } else if rlim.rlim_cur >= STACK_SIZE {
+ false
+ } else {
+ true
+ }
+ };
+
#[cfg(not(any(windows,unix)))]
let spawn_thread = true;
}
declare_lint! {
- MISSING_DOCS,
+ pub MISSING_DOCS,
Allow,
"detects missing documentation for public members"
}
use lint::FutureIncompatibleInfo;
mod bad_style;
-mod builtin;
+pub mod builtin;
mod types;
mod unused;
use borrow_check::nll::region_infer::RegionInferenceContext;
use borrow_check::nll::ToRegionVid;
+use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::mir::{Local, Mir};
-use rustc::ty::{self, RegionVid, TyCtxt};
+use rustc::ty::subst::{Substs, UnpackedKind};
+use rustc::ty::{self, RegionVid, Ty, TyCtxt};
use rustc_data_structures::indexed_vec::Idx;
use rustc_errors::DiagnosticBuilder;
use syntax::ast::Name;
self.give_name_from_error_region(tcx, mir_def_id, fr, counter, diag)
.or_else(|| {
- self.give_name_if_anonymous_region_appears_in_arguments(tcx, mir, fr, counter, diag)
+ self.give_name_if_anonymous_region_appears_in_arguments(
+ tcx, mir, mir_def_id, fr, counter, diag,
+ )
})
.or_else(|| {
self.give_name_if_anonymous_region_appears_in_upvars(tcx, mir, fr, counter, diag)
&self,
tcx: TyCtxt<'_, '_, 'tcx>,
mir: &Mir<'tcx>,
+ mir_def_id: DefId,
fr: RegionVid,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> Option<InternedString> {
let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
- let argument_index = self.universal_regions
+ let argument_index = self
+ .universal_regions
.unnormalized_input_tys
.iter()
.skip(implicit_inputs)
.position(|arg_ty| {
- debug!("give_name_if_anonymous_region_appears_in_arguments: arg_ty = {:?}", arg_ty);
+ debug!(
+ "give_name_if_anonymous_region_appears_in_arguments: arg_ty = {:?}",
+ arg_ty
+ );
tcx.any_free_region_meets(arg_ty, |r| r.to_region_vid() == fr)
- })?
- + implicit_inputs;
+ })?;
debug!(
"give_name_if_anonymous_region_appears_in_arguments: \
fr, argument_index, self.universal_regions.unnormalized_input_tys[argument_index],
);
+ let arg_ty =
+ self.universal_regions.unnormalized_input_tys[implicit_inputs + argument_index];
+ if let Some(region_name) = self.give_name_if_we_can_match_hir_ty_from_argument(
+ tcx,
+ mir_def_id,
+ fr,
+ arg_ty,
+ argument_index,
+ counter,
+ diag,
+ ) {
+ return Some(region_name);
+ }
+
let region_name = self.synthesize_region_name(counter);
- let argument_local = Local::new(argument_index + 1);
+ let argument_local = Local::new(argument_index + implicit_inputs + 1);
let argument_span = mir.local_decls[argument_local].source_info.span;
diag.span_label(
argument_span,
Some(region_name)
}
+ fn give_name_if_we_can_match_hir_ty_from_argument(
+ &self,
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ mir_def_id: DefId,
+ needle_fr: RegionVid,
+ argument_ty: Ty<'tcx>,
+ argument_index: usize,
+ counter: &mut usize,
+ diag: &mut DiagnosticBuilder<'_>,
+ ) -> Option<InternedString> {
+ let mir_node_id = tcx.hir.as_local_node_id(mir_def_id)?;
+ let fn_decl = tcx.hir.fn_decl(mir_node_id)?;
+ let argument_hir_ty: &hir::Ty = &fn_decl.inputs[argument_index];
+ match argument_hir_ty.node {
+ // This indicates a variable with no type annotation, like
+ // `|x|`... in that case, we can't highlight the type but
+ // must highlight the variable.
+ hir::TyInfer => None,
+
+ _ => self.give_name_if_we_can_match_hir_ty(
+ tcx,
+ needle_fr,
+ argument_ty,
+ argument_hir_ty,
+ counter,
+ diag,
+ ),
+ }
+ }
+
+ /// Attempts to highlight the specific part of a type annotation
+ /// that contains the anonymous reference we want to give a name
+ /// to. For example, we might produce an annotation like this:
+ ///
+ /// ```
+ /// | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
+ /// | - let's call the lifetime of this reference `'1`
+ /// ```
+ ///
+ /// the way this works is that we match up `argument_ty`, which is
+ /// a `Ty<'tcx>` (the internal form of the type) with
+ /// `argument_hir_ty`, a `hir::Ty` (the syntax of the type
+ /// annotation). We are descending through the types stepwise,
+ /// looking in to find the region `needle_fr` in the internal
+ /// type. Once we find that, we can use the span of the `hir::Ty`
+ /// to add the highlight.
+ ///
+ /// This is a somewhat imperfect process, so long the way we also
+ /// keep track of the **closest** type we've found. If we fail to
+ /// find the exact `&` or `'_` to highlight, then we may fall back
+ /// to highlighting that closest type instead.
+ fn give_name_if_we_can_match_hir_ty(
+ &self,
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ needle_fr: RegionVid,
+ argument_ty: Ty<'tcx>,
+ argument_hir_ty: &hir::Ty,
+ counter: &mut usize,
+ diag: &mut DiagnosticBuilder<'_>,
+ ) -> Option<InternedString> {
+ let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty)> = &mut Vec::new();
+
+ search_stack.push((argument_ty, argument_hir_ty));
+
+ let mut closest_match: &hir::Ty = argument_hir_ty;
+
+ while let Some((ty, hir_ty)) = search_stack.pop() {
+ // While we search, also track the closet match.
+ if tcx.any_free_region_meets(&ty, |r| r.to_region_vid() == needle_fr) {
+ closest_match = hir_ty;
+ }
+
+ match (&ty.sty, &hir_ty.node) {
+ // Check if the `argument_ty` is `&'X ..` where `'X`
+ // is the region we are looking for -- if so, and we have a `&T`
+ // on the RHS, then we want to highlight the `&` like so:
+ //
+ // &
+ // - let's call the lifetime of this reference `'1`
+ (ty::TyRef(region, referent_ty, _), hir::TyRptr(_lifetime, referent_hir_ty)) => {
+ if region.to_region_vid() == needle_fr {
+ let region_name = self.synthesize_region_name(counter);
+
+ // Just grab the first character, the `&`.
+ let codemap = tcx.sess.codemap();
+ let ampersand_span = codemap.start_point(hir_ty.span);
+
+ diag.span_label(
+ ampersand_span,
+ format!(
+ "let's call the lifetime of this reference `{}`",
+ region_name
+ ),
+ );
+
+ return Some(region_name);
+ }
+
+ // Otherwise, let's descend into the referent types.
+ search_stack.push((referent_ty, &referent_hir_ty.ty));
+ }
+
+ // Match up something like `Foo<'1>`
+ (ty::TyAdt(_adt_def, substs), hir::TyPath(hir::QPath::Resolved(None, path))) => {
+ if let Some(last_segment) = path.segments.last() {
+ if let Some(name) = self.match_adt_and_segment(
+ substs,
+ needle_fr,
+ last_segment,
+ counter,
+ diag,
+ search_stack,
+ ) {
+ return Some(name);
+ }
+ }
+ }
+
+ // The following cases don't have lifetimes, so we
+ // just worry about trying to match up the rustc type
+ // with the HIR types:
+ (ty::TyTuple(elem_tys), hir::TyTup(elem_hir_tys)) => {
+ search_stack.extend(elem_tys.iter().cloned().zip(elem_hir_tys));
+ }
+
+ (ty::TySlice(elem_ty), hir::TySlice(elem_hir_ty))
+ | (ty::TyArray(elem_ty, _), hir::TyArray(elem_hir_ty, _)) => {
+ search_stack.push((elem_ty, elem_hir_ty));
+ }
+
+ (ty::TyRawPtr(mut_ty), hir::TyPtr(mut_hir_ty)) => {
+ search_stack.push((mut_ty.ty, &mut_hir_ty.ty));
+ }
+
+ _ => {
+ // FIXME there are other cases that we could trace
+ }
+ }
+ }
+
+ let region_name = self.synthesize_region_name(counter);
+ diag.span_label(
+ closest_match.span,
+ format!("lifetime `{}` appears in this type", region_name),
+ );
+
+ return Some(region_name);
+ }
+
+ /// We've found an enum/struct/union type with the substitutions
+ /// `substs` and -- in the HIR -- a path type with the final
+ /// segment `last_segment`. Try to find a `'_` to highlight in
+ /// the generic args (or, if not, to produce new zipped pairs of
+ /// types+hir to search through).
+ fn match_adt_and_segment<'hir>(
+ &self,
+ substs: &'tcx Substs<'tcx>,
+ needle_fr: RegionVid,
+ last_segment: &'hir hir::PathSegment,
+ counter: &mut usize,
+ diag: &mut DiagnosticBuilder<'_>,
+ search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty)>,
+ ) -> Option<InternedString> {
+ // Did the user give explicit arguments? (e.g., `Foo<..>`)
+ let args = last_segment.args.as_ref()?;
+ let lifetime = self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
+ match lifetime.name {
+ hir::LifetimeName::Param(_)
+ | hir::LifetimeName::Static
+ | hir::LifetimeName::Underscore => {
+ let region_name = self.synthesize_region_name(counter);
+ let ampersand_span = lifetime.span;
+ diag.span_label(ampersand_span, format!("let's call this `{}`", region_name));
+ return Some(region_name);
+ }
+
+ hir::LifetimeName::Implicit => {
+ // In this case, the user left off the lifetime; so
+ // they wrote something like:
+ //
+ // ```
+ // x: Foo<T>
+ // ```
+ //
+ // where the fully elaborated form is `Foo<'_, '1,
+ // T>`. We don't consider this a match; instead we let
+ // the "fully elaborated" type fallback above handle
+ // it.
+ return None;
+ }
+ }
+ }
+
+ /// We've found an enum/struct/union type with the substitutions
+ /// `substs` and -- in the HIR -- a path with the generic
+ /// arguments `args`. If `needle_fr` appears in the args, return
+ /// the `hir::Lifetime` that corresponds to it. If not, push onto
+ /// `search_stack` the types+hir to search through.
+ fn try_match_adt_and_generic_args<'hir>(
+ &self,
+ substs: &'tcx Substs<'tcx>,
+ needle_fr: RegionVid,
+ args: &'hir hir::GenericArgs,
+ search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty)>,
+ ) -> Option<&'hir hir::Lifetime> {
+ for (kind, hir_arg) in substs.iter().zip(&args.args) {
+ match (kind.unpack(), hir_arg) {
+ (UnpackedKind::Lifetime(r), hir::GenericArg::Lifetime(lt)) => {
+ if r.to_region_vid() == needle_fr {
+ return Some(lt);
+ }
+ }
+
+ (UnpackedKind::Type(ty), hir::GenericArg::Type(hir_ty)) => {
+ search_stack.push((ty, hir_ty));
+ }
+
+ (UnpackedKind::Lifetime(_), _) | (UnpackedKind::Type(_), _) => {
+ // I *think* that HIR lowering should ensure this
+ // doesn't happen, even in erroneous
+ // programs. Else we should use delay-span-bug.
+ span_bug!(
+ hir_arg.span(),
+ "unmatched subst and hir arg: found {:?} vs {:?}",
+ kind,
+ hir_arg,
+ );
+ }
+ }
+ }
+
+ None
+ }
+
/// Find a closure upvar that contains `fr` and label it with a
/// fully elaborated type, returning something like `'1`. Result
/// looks like:
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> Option<InternedString> {
- let upvar_index = self.universal_regions
+ let upvar_index = self
+ .universal_regions
.defining_ty
.upvar_tys(tcx)
.position(|upvar_ty| {
tcx.any_free_region_meets(&upvar_ty, |r| r.to_region_vid() == fr)
})?;
+ let upvar_ty = self
+ .universal_regions
+ .defining_ty
+ .upvar_tys(tcx)
+ .nth(upvar_index);
+
debug!(
"give_name_if_anonymous_region_appears_in_upvars: \
found {:?} in upvar {} which has type {:?}",
- fr,
- upvar_index,
- self.universal_regions
- .defining_ty
- .upvar_tys(tcx)
- .nth(upvar_index),
+ fr, upvar_index, upvar_ty,
);
let region_name = self.synthesize_region_name(counter);
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
) -> Option<InternedString> {
- let return_ty = self.universal_regions
- .unnormalized_output_ty;
- debug!("give_name_if_anonymous_region_appears_in_output: return_ty = {:?}", return_ty);
+ let return_ty = self.universal_regions.unnormalized_output_ty;
+ debug!(
+ "give_name_if_anonymous_region_appears_in_output: return_ty = {:?}",
+ return_ty
+ );
if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) {
return None;
}
if ident.name == lookup_name && ns == namespace {
if filter_fn(name_binding.def()) {
// create the path
- let mut segms = path_segments.clone();
+ let mut segms = if self.session.rust_2018() && !in_module_is_extern {
+ // crate-local absolute paths start with `crate::` in edition 2018
+ // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
+ let mut full_segms = vec![
+ ast::PathSegment::from_ident(keywords::Crate.ident())
+ ];
+ full_segms.extend(path_segments.clone());
+ full_segms
+ } else {
+ path_segments.clone()
+ };
+
segms.push(ast::PathSegment::from_ident(ident));
let path = Path {
span: name_binding.span,
use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc::hir::map::definitions::DefPathData;
use rustc::hir::{self, ImplPolarity};
-use rustc::traits::{Clause, Clauses, DomainGoal, Goal, PolyDomainGoal, ProgramClause,
- WhereClause, FromEnv, WellFormed};
+use rustc::traits::{
+ Clause, Clauses, DomainGoal, FromEnv, Goal, PolyDomainGoal, ProgramClause, WellFormed,
+ WhereClause,
+};
use rustc::ty::query::Providers;
use rustc::ty::{self, Slice, TyCtxt};
use rustc_data_structures::fx::FxHashSet;
Predicate::RegionOutlives(predicate) => predicate.lower(),
Predicate::TypeOutlives(predicate) => predicate.lower(),
Predicate::Projection(predicate) => predicate.lower(),
- Predicate::WellFormed(ty) => ty::Binder::dummy(
- DomainGoal::WellFormed(WellFormed::Ty(*ty))
- ),
- Predicate::ObjectSafe(..) |
- Predicate::ClosureKind(..) |
- Predicate::Subtype(..) |
- Predicate::ConstEvaluatable(..) => {
- unimplemented!()
+ Predicate::WellFormed(ty) => {
+ ty::Binder::dummy(DomainGoal::WellFormed(WellFormed::Ty(*ty)))
}
+ Predicate::ObjectSafe(..)
+ | Predicate::ClosureKind(..)
+ | Predicate::Subtype(..)
+ | Predicate::ConstEvaluatable(..) => unimplemented!(),
}
}
}
-/// Transforms an existing goal into a FromEnv goal.
-///
-/// Used for lowered where clauses (see rustc guide).
+/// Used for implied bounds related rules (see rustc guide).
trait IntoFromEnvGoal {
+ /// Transforms an existing goal into a `FromEnv` goal.
fn into_from_env_goal(self) -> Self;
}
+/// Used for well-formedness related rules (see rustc guide).
+trait IntoWellFormedGoal {
+ /// Transforms an existing goal into a `WellFormed` goal.
+ fn into_well_formed_goal(self) -> Self;
+}
+
impl<'tcx> IntoFromEnvGoal for DomainGoal<'tcx> {
fn into_from_env_goal(self) -> DomainGoal<'tcx> {
use self::WhereClause::*;
match self {
- DomainGoal::Holds(Implemented(trait_ref)) => DomainGoal::FromEnv(
- FromEnv::Trait(trait_ref)
- ),
+ DomainGoal::Holds(Implemented(trait_ref)) => {
+ DomainGoal::FromEnv(FromEnv::Trait(trait_ref))
+ }
+ other => other,
+ }
+ }
+}
+
+impl<'tcx> IntoWellFormedGoal for DomainGoal<'tcx> {
+ fn into_well_formed_goal(self) -> DomainGoal<'tcx> {
+ use self::WhereClause::*;
+
+ match self {
+ DomainGoal::Holds(Implemented(trait_ref)) => {
+ DomainGoal::WellFormed(WellFormed::Trait(trait_ref))
+ }
other => other,
}
}
// `Implemented(Self: Trait<P1..Pn>)`
let impl_trait: DomainGoal = trait_pred.lower();
- // `FromEnv(Self: Trait<P1..Pn>)`
+ // `FromEnv(Self: Trait<P1..Pn>)`
let from_env_goal = impl_trait.into_from_env_goal().into_goal();
let hypotheses = tcx.intern_goals(&[from_env_goal]);
let clauses = iter::once(Clause::ForAll(ty::Binder::dummy(implemented_from_env)));
+ let where_clauses = &tcx.predicates_defined_on(def_id).predicates;
+
// Rule Implied-Bound-From-Trait
//
// For each where clause WC:
// ```
// `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`, for each where clause WC
- let where_clauses = &tcx.predicates_defined_on(def_id).predicates;
let implied_bound_clauses = where_clauses
.into_iter()
.map(|wc| wc.lower())
goal: goal.into_from_env_goal(),
hypotheses,
}))
-
.map(Clause::ForAll);
- tcx.mk_clauses(clauses.chain(implied_bound_clauses))
+ // Rule WellFormed-TraitRef
+ //
+ // Here `WC` denotes the set of all where clauses:
+ // ```
+ // forall<Self, P1..Pn> {
+ // WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)
+ // }
+ // ```
+
+ // `Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)`
+ let wf_conditions = iter::once(ty::Binder::dummy(trait_pred.lower()))
+ .chain(
+ where_clauses
+ .into_iter()
+ .map(|wc| wc.lower())
+ .map(|wc| wc.map_bound(|goal| goal.into_well_formed_goal()))
+ );
+
+ // `WellFormed(Self: Trait<P1..Pn>) :- Implemented(Self: Trait<P1..Pn>) && WellFormed(WC)`
+ let wf_clause = ProgramClause {
+ goal: DomainGoal::WellFormed(WellFormed::Trait(trait_pred)),
+ hypotheses: tcx.mk_goals(
+ wf_conditions.map(|wc| Goal::from_poly_domain_goal(wc, tcx)),
+ ),
+ };
+ let wf_clause = iter::once(Clause::ForAll(ty::Binder::dummy(wf_clause)));
+
+ tcx.mk_clauses(
+ clauses
+ .chain(implied_bound_clauses)
+ .chain(wf_clause)
+ )
}
fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Clauses<'tcx> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
) -> Clauses<'tcx> {
-
// Rule WellFormed-Type
//
// `struct Ty<P1..Pn> where WC1, ..., WCm`
let well_formed = ProgramClause {
goal: DomainGoal::WellFormed(WellFormed::Ty(ty)),
hypotheses: tcx.mk_goals(
- where_clauses.iter().cloned().map(|wc| Goal::from_poly_domain_goal(wc, tcx))
+ where_clauses
+ .iter()
+ .cloned()
+ .map(|wc| Goal::from_poly_domain_goal(wc, tcx)),
),
};
}
if let Some(clauses) = clauses {
- let mut err = self.tcx
+ let mut err = self
+ .tcx
.sess
.struct_span_err(attr.span, "program clause dump");
fcx.tcx.sess.err("language item required, but not found: `panic_info`");
}
}
+ }
+
+ // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
+ if let Some(alloc_error_handler_did) = fcx.tcx.lang_items().oom() {
+ if alloc_error_handler_did == fcx.tcx.hir.local_def_id(fn_id) {
+ if let Some(alloc_layout_did) = fcx.tcx.lang_items().alloc_layout() {
+ if declared_ret_ty.sty != ty::TyNever {
+ fcx.tcx.sess.span_err(
+ decl.output.span(),
+ "return type should be `!`",
+ );
+ }
+
+ let inputs = fn_sig.inputs();
+ let span = fcx.tcx.hir.span(fn_id);
+ if inputs.len() == 1 {
+ let arg_is_alloc_layout = match inputs[0].sty {
+ ty::TyAdt(ref adt, _) => {
+ adt.did == alloc_layout_did
+ },
+ _ => false,
+ };
+
+ if !arg_is_alloc_layout {
+ fcx.tcx.sess.span_err(
+ decl.inputs[0].span,
+ "argument should be `Layout`",
+ );
+ }
+ if let Node::NodeItem(item) = fcx.tcx.hir.get(fn_id) {
+ if let Item_::ItemFn(_, _, ref generics, _) = item.node {
+ if !generics.params.is_empty() {
+ fcx.tcx.sess.span_err(
+ span,
+ "`#[alloc_error_handler]` function should have no type \
+ parameters",
+ );
+ }
+ }
+ }
+ } else {
+ fcx.tcx.sess.span_err(span, "function should have one argument");
+ }
+ } else {
+ fcx.tcx.sess.err("language item required, but not found: `alloc_layout`");
+ }
+ }
}
(fcx, gen_ty)
let intra_link_resolution_failure_name = lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE.name;
let warnings_lint_name = lint::builtin::WARNINGS.name;
+ let missing_docs = rustc_lint::builtin::MISSING_DOCS.name;
let lints = lint::builtin::HardwiredLints.get_lints()
.into_iter()
.chain(rustc_lint::SoftLints.get_lints().into_iter())
let mut sess = session::build_session_(
sessopts, cpath, diagnostic_handler, codemap,
);
+
+ lint::builtin::HardwiredLints.get_lints()
+ .into_iter()
+ .chain(rustc_lint::SoftLints.get_lints().into_iter())
+ .filter_map(|lint| {
+ // We don't want to whitelist *all* lints so let's
+ // ignore those ones.
+ if lint.name == warnings_lint_name ||
+ lint.name == intra_link_resolution_failure_name ||
+ lint.name == missing_docs {
+ None
+ } else {
+ Some(lint)
+ }
+ })
+ .for_each(|l| {
+ sess.driver_lint_caps.insert(lint::LintId::of(l),
+ lint::Allow);
+ });
+
let codegen_backend = rustc_driver::get_codegen_backend(&sess);
let cstore = Rc::new(CStore::new(codegen_backend.metadata_loader()));
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
&sess);
let resolver = RefCell::new(resolver);
-
abort_on_err(driver::phase_3_run_analysis_passes(&*codegen_backend,
control,
&sess,
#[cfg(not(test))]
#[doc(hidden)]
-#[lang = "oom"]
+#[cfg_attr(stage0, lang = "oom")]
+#[cfg_attr(not(stage0), alloc_error_handler)]
#[unstable(feature = "alloc_internals", issue = "0")]
-pub extern fn rust_oom(layout: Layout) -> ! {
+pub fn rust_oom(layout: Layout) -> ! {
let hook = HOOK.load(Ordering::SeqCst);
let hook: fn(Layout) = if hook.is_null() {
default_alloc_error_hook
// std is implemented with unstable features, many of which are internal
// compiler details that will never be stable
#![feature(alloc)]
-#![feature(allocator_api)]
+#![feature(alloc_error_handler)]
#![feature(alloc_system)]
+#![feature(allocator_api)]
#![feature(allocator_internals)]
#![feature(allow_internal_unsafe)]
#![feature(allow_internal_unstable)]
self.span_until_char(sp, '{')
}
+ /// Returns a new span representing just the start-point of this span
+ pub fn start_point(&self, sp: Span) -> Span {
+ let pos = sp.lo().0;
+ let width = self.find_width_of_character_at_span(sp, false);
+ let corrected_start_position = pos.checked_add(width).unwrap_or(pos);
+ let end_point = BytePos(cmp::max(corrected_start_position, sp.lo().0));
+ sp.with_hi(end_point)
+ }
+
/// Returns a new span representing just the end-point of this span
pub fn end_point(&self, sp: Span) -> Span {
let pos = sp.hi().0;
// Allows async and await syntax
(active, async_await, "1.28.0", Some(50547), None),
+
+ // #[alloc_error_handler]
+ (active, alloc_error_handler, "1.29.0", Some(51540), None),
);
declare_features! (
"#[panic_implementation] is an unstable feature",
cfg_fn!(panic_implementation))),
+ ("alloc_error_handler", Normal, Gated(Stability::Unstable,
+ "alloc_error_handler",
+ "#[alloc_error_handler] is an unstable feature",
+ cfg_fn!(alloc_error_handler))),
+
// Crate level attributes
("crate_name", CrateLevel, Ungated),
("crate_type", CrateLevel, Ungated),
return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(F) & 0x3);
}
-#if LLVM_VERSION_GE(4, 0)
static DINode::DIFlags fromRust(LLVMRustDIFlags Flags) {
DINode::DIFlags Result = DINode::DIFlags::FlagZero;
-#else
-static unsigned fromRust(LLVMRustDIFlags Flags) {
- unsigned Result = 0;
-#endif
switch (visibility(Flags)) {
case LLVMRustDIFlags::FlagPrivate:
if (isSet(Flags & LLVMRustDIFlags::FlagBitField)) {
Result |= DINode::DIFlags::FlagBitField;
}
-#if LLVM_RUSTLLVM || LLVM_VERSION_GE(4, 0)
if (isSet(Flags & LLVMRustDIFlags::FlagNoReturn)) {
Result |= DINode::DIFlags::FlagNoReturn;
}
if (isSet(Flags & LLVMRustDIFlags::FlagMainSubprogram)) {
Result |= DINode::DIFlags::FlagMainSubprogram;
}
-#endif
return Result;
}
unsigned RuntimeVer, const char *SplitName) {
auto *File = unwrapDI<DIFile>(FileRef);
-#if LLVM_VERSION_GE(4, 0)
return wrap(Builder->createCompileUnit(Lang, File, Producer, isOptimized,
Flags, RuntimeVer, SplitName));
-#else
- return wrap(Builder->createCompileUnit(Lang, File->getFilename(),
- File->getDirectory(), Producer, isOptimized,
- Flags, RuntimeVer, SplitName));
-#endif
}
extern "C" LLVMMetadataRef
LLVMRustDIBuilderCreateBasicType(LLVMRustDIBuilderRef Builder, const char *Name,
uint64_t SizeInBits, uint32_t AlignInBits,
unsigned Encoding) {
- return wrap(Builder->createBasicType(Name, SizeInBits,
-#if LLVM_VERSION_LE(3, 9)
- AlignInBits,
-#endif
- Encoding));
+ return wrap(Builder->createBasicType(Name, SizeInBits, Encoding));
}
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreatePointerType(
LLVMMetadataRef Decl = nullptr, uint32_t AlignInBits = 0) {
llvm::GlobalVariable *InitVal = cast<llvm::GlobalVariable>(unwrap(V));
-#if LLVM_VERSION_GE(4, 0)
llvm::DIExpression *InitExpr = nullptr;
if (llvm::ConstantInt *IntVal = llvm::dyn_cast<llvm::ConstantInt>(InitVal)) {
InitExpr = Builder->createConstantValueExpression(
InitVal->setMetadata("dbg", VarExpr);
return wrap(VarExpr);
-#else
- return wrap(Builder->createGlobalVariable(
- unwrapDI<DIDescriptor>(Context), Name, LinkageName,
- unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), IsLocalToUnit,
- InitVal, unwrapDIPtr<MDNode>(Decl)));
-#endif
}
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable(
if (Tag == 0x100) { // DW_TAG_auto_variable
return wrap(Builder->createAutoVariable(
unwrapDI<DIDescriptor>(Scope), Name, unwrapDI<DIFile>(File), LineNo,
- unwrapDI<DIType>(Ty), AlwaysPreserve, fromRust(Flags)
-#if LLVM_VERSION_GE(4, 0)
- ,
- AlignInBits
-#endif
- ));
+ unwrapDI<DIType>(Ty), AlwaysPreserve, fromRust(Flags), AlignInBits));
} else {
return wrap(Builder->createParameterVariable(
unwrapDI<DIDescriptor>(Scope), Name, ArgNo, unwrapDI<DIFile>(File),
// scalar value.
// compile-flags: -C no-prepopulate-passes
-// min-llvm-version 4.0
-
#![crate_type = "lib"]
x
}
-// CHECK: i16 @enum_id_2(i16)
+// CHECK: { i8, i8 } @enum_id_2(i1 zeroext %x.0, i8 %x.1)
#[no_mangle]
pub fn enum_id_2(x: Option<u8>) -> Option<u8> {
x
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// min-llvm-version 4.0
// compile-flags: -O
// ignore-x86
// ignore-arm
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// min-llvm-version 4.0
// compile-flags: -O
+// min-llvm-version 6.0
#![crate_type="rlib"]
// ignore-tidy-linelength
// ignore-windows
// ignore-macos
-// min-llvm-version 4.0
// compile-flags: -g -C no-prepopulate-passes
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// This test depends on a patch that was committed to upstream LLVM
-// before 4.0, formerly backported to the Rust LLVM fork.
-
// ignore-tidy-linelength
// ignore-windows
// ignore-macos
-// min-llvm-version 4.0
// compile-flags: -g -C no-prepopulate-passes
// compile-flags: -g -C no-prepopulate-passes
// ignore-tidy-linelength
-// min-llvm-version 4.0
#![crate_type = "lib"]
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// CHECK: define { i8, i8 } @pair_bool_bool(i1 zeroext %pair.0, i1 zeroext %pair.1)
+#[no_mangle]
+pub fn pair_bool_bool(pair: (bool, bool)) -> (bool, bool) {
+ pair
+}
+
+// CHECK: define { i8, i32 } @pair_bool_i32(i1 zeroext %pair.0, i32 %pair.1)
+#[no_mangle]
+pub fn pair_bool_i32(pair: (bool, i32)) -> (bool, i32) {
+ pair
+}
+
+// CHECK: define { i32, i8 } @pair_i32_bool(i32 %pair.0, i1 zeroext %pair.1)
+#[no_mangle]
+pub fn pair_i32_bool(pair: (i32, bool)) -> (i32, bool) {
+ pair
+}
+
+// CHECK: define { i8, i8 } @pair_and_or(i1 zeroext %arg0.0, i1 zeroext %arg0.1)
+#[no_mangle]
+pub fn pair_and_or((a, b): (bool, bool)) -> (bool, bool) {
+ // Make sure it can operate directly on the unpacked args
+ // CHECK: and i1 %arg0.0, %arg0.1
+ // CHECK: or i1 %arg0.0, %arg0.1
+ (a && b, a || b)
+}
+
+// CHECK: define void @pair_branches(i1 zeroext %arg0.0, i1 zeroext %arg0.1)
+#[no_mangle]
+pub fn pair_branches((a, b): (bool, bool)) {
+ // Make sure it can branch directly on the unpacked bool args
+ // CHECK: br i1 %arg0.0
+ if a {
+ println!("Hello!");
+ }
+ // CHECK: br i1 %arg0.1
+ if b {
+ println!("Goodbye!");
+ }
+}
// ignore-wasm
// ignore-emscripten
// ignore-windows
-// min-system-llvm-version 5.0
// compile-flags: -C no-prepopulate-passes
#![crate_type = "lib"]
// ignore-tidy-linelength
// ignore-windows
// ignore-macos
-// min-system-llvm-version 5.1
+// min-llvm-version 6.0
// compile-flags: -g -C no-prepopulate-passes
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:-C panic=abort
+
+#![feature(alloc_error_handler, panic_implementation)]
+#![no_std]
+#![no_main]
+
+use core::alloc::Layout;
+
+#[alloc_error_handler]
+fn oom(
+ info: &Layout, //~ ERROR argument should be `Layout`
+) -> () //~ ERROR return type should be `!`
+{
+ loop {}
+}
+
+#[panic_implementation]
+fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:-C panic=abort
+
+#![feature(alloc_error_handler, panic_implementation)]
+#![no_std]
+#![no_main]
+
+struct Layout;
+
+#[alloc_error_handler]
+fn oom(
+ info: Layout, //~ ERROR argument should be `Layout`
+) { //~ ERROR return type should be `!`
+ loop {}
+}
+
+#[panic_implementation]
+fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:-C panic=abort
+
+#![feature(alloc_error_handler, panic_implementation)]
+#![no_std]
+#![no_main]
+
+struct Layout;
+
+#[alloc_error_handler]
+fn oom() -> ! { //~ ERROR function should have one argument
+ loop {}
+}
+
+#[panic_implementation]
+fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:-C panic=abort
+
+#![no_std]
+#![no_main]
+
+use core::alloc::Layout;
+
+#[alloc_error_handler] //~ ERROR #[alloc_error_handler] is an unstable feature (see issue #51540)
+fn oom(info: Layout) -> ! {
+ loop {}
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// min-llvm-version 5.0
// ignore-emscripten
// Test that the simd_reduce_{op} intrinsics produce ok-ish error
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// asmjs can't even pass i128 as arguments or return values, so ignore it.
-// this will hopefully be fixed by the LLVM 5 upgrade (#43370)
-// ignore-asmjs
// ignore-emscripten
// compile-flags: -Z lower_128bit_ops=yes -C debug_assertions=no
-
-# min-llvm-version 4.0
# ignore-msvc
-include ../tools.mk
#![no_main]
#![no_std]
+use core::alloc::Layout;
use core::panic::PanicInfo;
#[panic_implementation]
fn eh() {}
#[lang = "oom"]
-fn oom() {}
+fn oom(_: Layout) -> ! {
+ loop {}
+}
bool runOnFunction(Function &F) override;
-#if LLVM_VERSION_MAJOR >= 4
- StringRef
-#else
- const char *
-#endif
- getPassName() const override {
+ StringRef getPassName() const override {
return "Some LLVM pass";
}
bool runOnModule(Module &M) override;
-#if LLVM_VERSION_MAJOR >= 4
- StringRef
-#else
- const char *
-#endif
- getPassName() const override {
+ StringRef getPassName() const override {
return "Some LLVM pass";
}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-cloudabi no processes
+// ignore-emscripten no processes
+
+use std::alloc::{Layout, handle_alloc_error};
+use std::env;
+use std::process::Command;
+use std::str;
+
+fn main() {
+ if env::args().len() > 1 {
+ handle_alloc_error(Layout::new::<[u8; 42]>())
+ }
+
+ let me = env::current_exe().unwrap();
+ let output = Command::new(&me).arg("next").output().unwrap();
+ assert!(!output.status.success(), "{:?} is a success", output.status);
+ assert_eq!(str::from_utf8(&output.stderr).unwrap(), "memory allocation of 42 bytes failed");
+}
// except according to those terms.
// check that we don't have linear stack usage with multiple calls to `push`
-// min-llvm-version 4.0
#![feature(test)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// min-llvm-version 5.0
// ignore-emscripten
// Test that the simd_reduce_{op} intrinsics produce the correct results.
// ignore-emscripten no processes
// ignore-musl FIXME #31506
// ignore-pretty
-// min-system-llvm-version 5.0
// compile-flags: -C lto
// no-prefer-dynamic
// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-musl FIXME #31506
-// min-system-llvm-version 5.0
use std::mem;
use std::process::Command;
// except according to those terms.
// compile-flags: -Z thinlto -C codegen-units=2
-// min-llvm-version 4.0
#[global_allocator]
static A: std::alloc::System = std::alloc::System;
// compile-flags: -Clto=thin
// no-prefer-dynamic
-// min-llvm-version 4.0
fn main() {
println!("hello!");
// except according to those terms.
// aux-build:dylib.rs
-// min-llvm-version 4.0
extern crate dylib;
// aux-build:msvc-imp-present.rs
// compile-flags: -Z thinlto -C codegen-units=8
-// min-llvm-version: 4.0
// no-prefer-dynamic
// On MSVC we have a "hack" where we emit symbols that look like `_imp_$name`
// except according to those terms.
// compile-flags: -Z thinlto -C codegen-units=8 -O
-// min-llvm-version 4.0
// ignore-emscripten can't inspect instructions on emscripten
// We want to assert here that ThinLTO will inline across codegen units. There's
// compile-flags: -C codegen-units=8 -O -C lto=thin
// aux-build:thin-lto-inlines-aux.rs
-// min-llvm-version 4.0
// no-prefer-dynamic
// ignore-emscripten can't inspect instructions on emscripten
// compile-flags: -C codegen-units=8 -Z thinlto
// ignore-windows
-// min-llvm-version 4.0
#![feature(linkage)]
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+// This test purpose is to check that unused_imports lint isn't fired
+// by rustdoc. Why would it? Because when rustdoc is running, it uses
+// "everybody-loops" which replaces parts of code with "loop {}" to get
+// huge performance improvements.
+
+#![deny(unused_imports)]
+
+use std::fs::File;
+
+pub fn f() {
+ let _: File;
+}
| ---------------- lifetime `'2` appears in the type of `lines_to_use`
LL | //~^ NOTE cannot infer an appropriate lifetime
LL | let push_id = |installed_id: &CrateId| {
- | ------------ lifetime `'1` appears in this argument
+ | - let's call the lifetime of this reference `'1`
...
LL | lines_to_use.push(installed_id);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2`
= note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
= note: FromEnv(Self: Foo) :- FromEnv(Self: Bar).
= note: Implemented(Self: Bar) :- FromEnv(Self: Bar).
+ = note: WellFormed(Self: Bar) :- Implemented(Self: Bar), WellFormed(Self: Foo), WellFormed(Self: Foo).
error: program clause dump
--> $DIR/lower_env1.rs:19:1
= note: Implemented(Self: Bar) :- FromEnv(Self: Bar).
= note: Implemented(Self: Foo) :- FromEnv(Self: Foo).
= note: Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized).
+ = note: WellFormed(Self: Bar) :- Implemented(Self: Bar), WellFormed(Self: Foo), WellFormed(Self: Foo).
+ = note: WellFormed(Self: Foo) :- Implemented(Self: Foo).
+ = note: WellFormed(Self: std::marker::Sized) :- Implemented(Self: std::marker::Sized).
error: aborting due to 2 previous errors
= note: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
= note: FromEnv(U: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>).
= note: Implemented(Self: Foo<S, T, U>) :- FromEnv(Self: Foo<S, T, U>).
+ = note: WellFormed(Self: Foo<S, T, U>) :- Implemented(Self: Foo<S, T, U>), WellFormed(S: std::marker::Sized), WellFormed(T: std::marker::Sized), WellFormed(U: std::marker::Sized).
error: aborting due to previous error
= note: FromEnv(F: std::ops::Fn<(&'a (u8, u16),)>) :- FromEnv(Self: Foo<F>).
= note: Implemented(Self: Foo<F>) :- FromEnv(Self: Foo<F>).
= note: ProjectionEq(<F as std::ops::FnOnce<(&'a (u8, u16),)>>::Output == &'a u8) :- FromEnv(Self: Foo<F>).
+ = note: WellFormed(Self: Foo<F>) :- Implemented(Self: Foo<F>), WellFormed(F: std::marker::Sized), forall<> { WellFormed(F: std::ops::Fn<(&'a (u8, u16),)>) }, forall<> { ProjectionEq(<F as std::ops::FnOnce<(&'a (u8, u16),)>>::Output == &'a u8) }.
error: aborting due to previous error
= note: Implemented(Self: Foo<'a, 'b, S, T, U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
= note: RegionOutlives('a : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
= note: TypeOutlives(U : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>).
+ = note: WellFormed(Self: Foo<'a, 'b, S, T, U>) :- Implemented(Self: Foo<'a, 'b, S, T, U>), WellFormed(S: std::marker::Sized), WellFormed(T: std::marker::Sized), WellFormed(S: std::fmt::Debug), WellFormed(T: std::borrow::Borrow<U>), RegionOutlives('a : 'b), TypeOutlives(U : 'b).
error: aborting due to previous error
LL | let mut f: Option<&u32> = None;
| ----- lifetime `'2` appears in the type of `f`
LL | closure_expecting_bound(|x: &u32| {
- | - lifetime `'1` appears in this argument
+ | - let's call the lifetime of this reference `'1`
LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
| ^^^^^^^^^^^ free region requires that `'1` must outlive `'2`
| ----- lifetime `'2` appears in the type of `f`
...
LL | closure_expecting_bound(|x: &'x u32| {
- | - lifetime `'1` appears in this argument
+ | - let's call the lifetime of this reference `'1`
...
LL | f = Some(x);
| ^^^^^^^^^^^ free region requires that `'1` must outlive `'2`
--> $DIR/static-return-lifetime-infered.rs:17:9
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
- | ----- lifetime `'1` appears in this argument
+ | - let's call the lifetime of this reference `'1`
LL | self.x.iter().map(|a| a.0)
| ^^^^^^ cast requires that `'1` must outlive `'static`
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C panic=abort
+// no-prefer-dynamic
+
+#![no_std]
+#![crate_type = "staticlib"]
+#![feature(panic_implementation, alloc_error_handler, alloc)]
+
+#[panic_implementation]
+fn panic(_: &core::panic::PanicInfo) -> ! {
+ loop {}
+}
+
+extern crate alloc;
+
+#[global_allocator]
+static A: MyAlloc = MyAlloc;
+
+struct MyAlloc;
+
+unsafe impl core::alloc::GlobalAlloc for MyAlloc {
+ unsafe fn alloc(&self, _: core::alloc::Layout) -> *mut u8 { 0 as _ }
+ unsafe fn dealloc(&self, _: *mut u8, _: core::alloc::Layout) {}
+}
--- /dev/null
+error: `#[alloc_error_handler]` function required, but not found
+
+error: aborting due to previous error
+
#![no_std]
#![crate_type = "staticlib"]
-#![feature(panic_implementation, lang_items, alloc)]
+#![feature(panic_implementation, alloc_error_handler, alloc)]
#[panic_implementation]
fn panic(_: &core::panic::PanicInfo) -> ! {
loop {}
}
-#[lang = "oom"]
-fn oom() {}
+#[alloc_error_handler]
+fn oom(_: core::alloc::Layout) -> ! {
+ loop {}
+}
extern crate alloc;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition 2018
+
+// The local `use` suggestion should start with `crate::` (but the
+// standard-library suggestions should not, obviously).
+
+mod plumbing {
+ pub struct Drain;
+}
+
+fn main() {
+ let _d = Drain {};
+ //~^ ERROR cannot find struct, variant or union type `Drain` in this scope
+}
--- /dev/null
+error[E0422]: cannot find struct, variant or union type `Drain` in this scope
+ --> $DIR/issue-52202-use-suggestions.rs:21:14
+ |
+LL | let _d = Drain {};
+ | ^^^^^ not found in this scope
+help: possible candidates are found in other modules, you can import them into scope
+ |
+LL | use crate::plumbing::Drain;
+ |
+LL | use std::collections::binary_heap::Drain;
+ |
+LL | use std::collections::hash_map::Drain;
+ |
+LL | use std::collections::hash_set::Drain;
+ |
+and 3 other candidates
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0422`.
--> $DIR/dyn-trait-underscore.rs:18:5
|
LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
- | ----- lifetime `'1` appears in this argument
+ | - let's call the lifetime of this reference `'1`
LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
| ^^^^^^^^^^^^^^^^^^^^^^ cast requires that `'1` must outlive `'static`