From 98dee04baefedc3b00077789edceface65ebc343 Mon Sep 17 00:00:00 2001 From: Vadzim Dambrouski Date: Tue, 16 Jan 2018 16:00:31 +0300 Subject: Add run-make test for no_integrated_as flag. --- src/test/run-make/no-integrated-as/Makefile | 7 +++++++ src/test/run-make/no-integrated-as/hello.rs | 13 +++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/test/run-make/no-integrated-as/Makefile create mode 100644 src/test/run-make/no-integrated-as/hello.rs (limited to 'src/test') diff --git a/src/test/run-make/no-integrated-as/Makefile b/src/test/run-make/no-integrated-as/Makefile new file mode 100644 index 00000000000..78e3025b99a --- /dev/null +++ b/src/test/run-make/no-integrated-as/Makefile @@ -0,0 +1,7 @@ +-include ../tools.mk + +all: +ifeq ($(TARGET),x86_64-unknown-linux-gnu) + $(RUSTC) hello.rs -C no_integrated_as + $(call RUN,hello) +endif diff --git a/src/test/run-make/no-integrated-as/hello.rs b/src/test/run-make/no-integrated-as/hello.rs new file mode 100644 index 00000000000..68e7f6d94d1 --- /dev/null +++ b/src/test/run-make/no-integrated-as/hello.rs @@ -0,0 +1,13 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + println!("Hello, world!"); +} -- cgit 1.4.1-3-g733a5 From 9b95e914a1f6537563b885c2ffbdb069e64cc14c Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 15 Jan 2018 01:48:19 +0200 Subject: rustc_trans: ignore trailing padding larger than 8 bytes. --- src/librustc_trans/cabi_x86_64.rs | 12 ++++++------ src/test/run-pass/align-with-extern-c-fn.rs | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src/test') diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index 6db18bfecf2..681b7f55273 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -179,12 +179,12 @@ fn cast_target(cls: &[Class], size: Size) -> CastTarget { let mut i = 0; let lo = reg_component(cls, &mut i, size).unwrap(); let offset = Size::from_bytes(8) * (i as u64); - let target = if size <= offset { - CastTarget::from(lo) - } else { - let hi = reg_component(cls, &mut i, size - offset).unwrap(); - CastTarget::Pair(lo, hi) - }; + let mut target = CastTarget::from(lo); + if size > offset { + if let Some(hi) = reg_component(cls, &mut i, size - offset) { + target = CastTarget::Pair(lo, hi); + } + } assert_eq!(reg_component(cls, &mut i, Size::from_bytes(0)), None); target } diff --git a/src/test/run-pass/align-with-extern-c-fn.rs b/src/test/run-pass/align-with-extern-c-fn.rs index db25960df4c..15e3b4b03eb 100644 --- a/src/test/run-pass/align-with-extern-c-fn.rs +++ b/src/test/run-pass/align-with-extern-c-fn.rs @@ -14,10 +14,10 @@ #![feature(attr_literals)] #[repr(align(16))] -pub struct A { - y: i64, -} +pub struct A(i64); pub extern "C" fn foo(x: A) {} -fn main() {} +fn main() { + foo(A(0)); +} -- cgit 1.4.1-3-g733a5 From cbeebc5b2cde6cb4f6cec9cd0cdfbd5d2c15dc39 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Mon, 15 Jan 2018 01:18:48 +0200 Subject: rustc_trans: take into account primitives larger than 8 bytes. --- src/librustc_trans/cabi_x86_64.rs | 98 +++++++++++++++++---------------------- src/test/run-pass/issue-38763.rs | 21 +++++++++ 2 files changed, 64 insertions(+), 55 deletions(-) create mode 100644 src/test/run-pass/issue-38763.rs (limited to 'src/test') diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index 6db18bfecf2..630762602d0 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -16,9 +16,11 @@ use context::CodegenCx; use rustc::ty::layout::{self, TyLayout, Size}; -#[derive(Clone, Copy, PartialEq, Debug)] +/// Classification of "eightbyte" components. +// NB: the order of the variants is from general to specific, +// such that `unify(a, b)` is the "smaller" of `a` and `b`. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] enum Class { - None, Int, Sse, SseUp @@ -32,29 +34,10 @@ const LARGEST_VECTOR_SIZE: usize = 512; const MAX_EIGHTBYTES: usize = LARGEST_VECTOR_SIZE / 64; fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>) - -> Result<[Class; MAX_EIGHTBYTES], Memory> { - fn unify(cls: &mut [Class], - off: Size, - c: Class) { - let i = (off.bytes() / 8) as usize; - let to_write = match (cls[i], c) { - (Class::None, _) => c, - (_, Class::None) => return, - - (Class::Int, _) | - (_, Class::Int) => Class::Int, - - (Class::Sse, _) | - (_, Class::Sse) => Class::Sse, - - (Class::SseUp, Class::SseUp) => Class::SseUp - }; - cls[i] = to_write; - } - + -> Result<[Option; MAX_EIGHTBYTES], Memory> { fn classify<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, layout: TyLayout<'tcx>, - cls: &mut [Class], + cls: &mut [Option], off: Size) -> Result<(), Memory> { if !off.is_abi_aligned(layout.align) { @@ -64,31 +47,20 @@ fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>) return Ok(()); } - match layout.abi { - layout::Abi::Uninhabited => {} + let mut c = match layout.abi { + layout::Abi::Uninhabited => return Ok(()), layout::Abi::Scalar(ref scalar) => { - let reg = match scalar.value { + match scalar.value { layout::Int(..) | layout::Pointer => Class::Int, layout::F32 | layout::F64 => Class::Sse - }; - unify(cls, off, reg); - } - - layout::Abi::Vector { ref element, count } => { - unify(cls, off, Class::Sse); - - // everything after the first one is the upper - // half of a register. - let stride = element.value.size(cx); - for i in 1..count { - let field_off = off + stride * i; - unify(cls, field_off, Class::SseUp); } } + layout::Abi::Vector { .. } => Class::Sse, + layout::Abi::ScalarPair(..) | layout::Abi::Aggregate { .. } => { match layout.variants { @@ -97,12 +69,26 @@ fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>) let field_off = off + layout.fields.offset(i); classify(cx, layout.field(cx, i), cls, field_off)?; } + return Ok(()); } layout::Variants::Tagged { .. } | layout::Variants::NicheFilling { .. } => return Err(Memory), } } + }; + + // Fill in `cls` for scalars (Int/Sse) and vectors (Sse). + let first = (off.bytes() / 8) as usize; + let last = ((off.bytes() + layout.size.bytes() - 1) / 8) as usize; + for cls in &mut cls[first..=last] { + *cls = Some(cls.map_or(c, |old| old.min(c))); + + // Everything after the first Sse "eightbyte" + // component is the upper half of a register. + if c == Class::Sse { + c = Class::SseUp; + } } Ok(()) @@ -113,23 +99,23 @@ fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>) return Err(Memory); } - let mut cls = [Class::None; MAX_EIGHTBYTES]; + let mut cls = [None; MAX_EIGHTBYTES]; classify(cx, arg.layout, &mut cls, Size::from_bytes(0))?; if n > 2 { - if cls[0] != Class::Sse { + if cls[0] != Some(Class::Sse) { return Err(Memory); } - if cls[1..n].iter().any(|&c| c != Class::SseUp) { + if cls[1..n].iter().any(|&c| c != Some(Class::SseUp)) { return Err(Memory); } } else { let mut i = 0; while i < n { - if cls[i] == Class::SseUp { - cls[i] = Class::Sse; - } else if cls[i] == Class::Sse { + if cls[i] == Some(Class::SseUp) { + cls[i] = Some(Class::Sse); + } else if cls[i] == Some(Class::Sse) { i += 1; - while i != n && cls[i] == Class::SseUp { i += 1; } + while i != n && cls[i] == Some(Class::SseUp) { i += 1; } } else { i += 1; } @@ -139,14 +125,14 @@ fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>) Ok(cls) } -fn reg_component(cls: &[Class], i: &mut usize, size: Size) -> Option { +fn reg_component(cls: &[Option], i: &mut usize, size: Size) -> Option { if *i >= cls.len() { return None; } match cls[*i] { - Class::None => None, - Class::Int => { + None => None, + Some(Class::Int) => { *i += 1; Some(match size.bytes() { 1 => Reg::i8(), @@ -156,8 +142,10 @@ fn reg_component(cls: &[Class], i: &mut usize, size: Size) -> Option { _ => Reg::i64() }) } - Class::Sse => { - let vec_len = 1 + cls[*i+1..].iter().take_while(|&&c| c == Class::SseUp).count(); + Some(Class::Sse) => { + let vec_len = 1 + cls[*i+1..].iter() + .take_while(|&&c| c == Some(Class::SseUp)) + .count(); *i += vec_len; Some(if vec_len == 1 { match size.bytes() { @@ -171,11 +159,11 @@ fn reg_component(cls: &[Class], i: &mut usize, size: Size) -> Option { } }) } - c => bug!("reg_component: unhandled class {:?}", c) + Some(c) => bug!("reg_component: unhandled class {:?}", c) } } -fn cast_target(cls: &[Class], size: Size) -> CastTarget { +fn cast_target(cls: &[Option], size: Size) -> CastTarget { let mut i = 0; let lo = reg_component(cls, &mut i, size).unwrap(); let offset = Size::from_bytes(8) * (i as u64); @@ -203,8 +191,8 @@ pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tc Ok(ref cls) if is_arg => { for &c in cls { match c { - Class::Int => needed_int += 1, - Class::Sse => needed_sse += 1, + Some(Class::Int) => needed_int += 1, + Some(Class::Sse) => needed_sse += 1, _ => {} } } diff --git a/src/test/run-pass/issue-38763.rs b/src/test/run-pass/issue-38763.rs new file mode 100644 index 00000000000..4bf9513d64f --- /dev/null +++ b/src/test/run-pass/issue-38763.rs @@ -0,0 +1,21 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(i128_type)] + +#[repr(C)] +pub struct Foo(i128); + +#[no_mangle] +pub extern "C" fn foo(x: Foo) -> Foo { x } + +fn main() { + foo(Foo(1)); +} -- cgit 1.4.1-3-g733a5 From 072c3daa4cb6e1a8958ad9d61ebc7e062d570eac Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Jan 2018 17:19:23 -0500 Subject: track recursion limit when expanding existential impl trait --- src/librustc/infer/region_constraints/mod.rs | 2 +- src/librustc/traits/project.rs | 16 ++++++++- .../borrow_check/nll/type_check/mod.rs | 3 ++ .../impl-trait/infinite-impl-trait-issue-38064.rs | 39 ++++++++++++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/impl-trait/infinite-impl-trait-issue-38064.rs (limited to 'src/test') diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index 72740dd40be..68d81a2dee3 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -82,7 +82,7 @@ pub type VarOrigins = IndexVec; /// Describes constraints between the region variables and other /// regions, as well as other conditions that must be verified, or /// assumptions that can be made. -#[derive(Default)] +#[derive(Debug, Default)] pub struct RegionConstraintData<'tcx> { /// Constraints of the form `A <= B`, where either `A` or `B` can /// be a region variable (or neither, as it happens). diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 3342d13dd6e..d34649782ba 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -293,9 +293,23 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, Reveal::UserFacing => ty, Reveal::All => { + let recursion_limit = self.tcx().sess.recursion_limit.get(); + if self.depth >= recursion_limit { + let obligation = Obligation::with_depth( + self.cause.clone(), + recursion_limit, + self.param_env, + ty, + ); + self.selcx.infcx().report_overflow_error(&obligation, true); + } + let generic_ty = self.tcx().type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx(), substs); - self.fold_ty(concrete_ty) + self.depth += 1; + let folded_ty = self.fold_ty(concrete_ty); + self.depth -= 1; + folded_ty } } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 901b73c610e..9dcd4435580 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -681,6 +681,8 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let data = self.infcx.take_and_reset_region_constraints(); if !data.is_empty() { + debug!("fully_perform_op: constraints generated at {:?} are {:#?}", + locations, data); self.constraints .outlives_sets .push(OutlivesSet { locations, data }); @@ -1539,6 +1541,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { where T: fmt::Debug + TypeFoldable<'tcx>, { + debug!("normalize(value={:?}, location={:?})", value, location); self.fully_perform_op(location.at_self(), |this| { let mut selcx = traits::SelectionContext::new(this.infcx); let cause = this.misc(this.last_span); diff --git a/src/test/compile-fail/impl-trait/infinite-impl-trait-issue-38064.rs b/src/test/compile-fail/impl-trait/infinite-impl-trait-issue-38064.rs new file mode 100644 index 00000000000..abde9689bd6 --- /dev/null +++ b/src/test/compile-fail/impl-trait/infinite-impl-trait-issue-38064.rs @@ -0,0 +1,39 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that attempts to construct infinite types via impl trait fail +// in a graceful way. +// +// Regression test for #38064. + +// error-pattern:overflow evaluating the requirement `impl Quux` + +#![feature(conservative_impl_trait)] + +trait Quux {} + +fn foo() -> impl Quux { + struct Foo(T); + impl Quux for Foo {} + Foo(bar()) +} + +fn bar() -> impl Quux { + struct Bar(T); + impl Quux for Bar {} + Bar(foo()) +} + +// effectively: +// struct Foo(Bar); +// struct Bar(Foo); +// should produce an error about infinite size + +fn main() { foo(); } -- cgit 1.4.1-3-g733a5 From 768cbbcd9e21c75565dad4714346b0d0028d331c Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 19 Jan 2018 19:58:46 +0000 Subject: Fix type inhabitedness check for arrays Arrays of uninhabited types were considered to also be uninhabited if their length had not been evaluated, causing unsoundness. --- src/librustc/ty/inhabitedness/mod.rs | 9 +++++---- src/test/compile-fail/empty-never-array.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 src/test/compile-fail/empty-never-array.rs (limited to 'src/test') diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 0072512464a..8cf5b431cf1 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -262,10 +262,11 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { })) }, TyArray(ty, len) => { - if len.val.to_const_int().and_then(|i| i.to_u64()) == Some(0) { - DefIdForest::empty() - } else { - ty.uninhabited_from(visited, tcx) + match len.val.to_const_int().and_then(|i| i.to_u64()) { + Some(n) if n != 0 => ty.uninhabited_from(visited, tcx), + // If the array is definitely non-empty, it's uninhabited if + // the type of its elements is uninhabited. + _ => DefIdForest::empty() } } TyRef(_, ref tm) => { diff --git a/src/test/compile-fail/empty-never-array.rs b/src/test/compile-fail/empty-never-array.rs new file mode 100644 index 00000000000..1dc45a1a884 --- /dev/null +++ b/src/test/compile-fail/empty-never-array.rs @@ -0,0 +1,26 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(never_type)] + +enum Helper { + T(T, [!; 0]), + #[allow(dead_code)] + U(U), +} + +fn transmute(t: T) -> U { + let Helper::U(u) = Helper::T(t, []); //~ ERROR refutable pattern in local binding: `T(_, _)` not covered + u +} + +fn main() { + println!("{:?}", transmute::<&str, (*const u8, u64)>("type safety")); +} -- cgit 1.4.1-3-g733a5 From c4d0bb398b548dafba2346f3f3be9284909643f0 Mon Sep 17 00:00:00 2001 From: varkor Date: Fri, 19 Jan 2018 21:00:35 +0000 Subject: Fix tidy error --- src/librustc/ty/inhabitedness/mod.rs | 2 +- src/test/compile-fail/empty-never-array.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/test') diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 8cf5b431cf1..93e4cd9adf8 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -263,9 +263,9 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { }, TyArray(ty, len) => { match len.val.to_const_int().and_then(|i| i.to_u64()) { - Some(n) if n != 0 => ty.uninhabited_from(visited, tcx), // If the array is definitely non-empty, it's uninhabited if // the type of its elements is uninhabited. + Some(n) if n != 0 => ty.uninhabited_from(visited, tcx), _ => DefIdForest::empty() } } diff --git a/src/test/compile-fail/empty-never-array.rs b/src/test/compile-fail/empty-never-array.rs index 1dc45a1a884..53b24e17319 100644 --- a/src/test/compile-fail/empty-never-array.rs +++ b/src/test/compile-fail/empty-never-array.rs @@ -17,7 +17,8 @@ enum Helper { } fn transmute(t: T) -> U { - let Helper::U(u) = Helper::T(t, []); //~ ERROR refutable pattern in local binding: `T(_, _)` not covered + let Helper::U(u) = Helper::T(t, []); + //~^ ERROR refutable pattern in local binding: `T(_, _)` not covered u } -- cgit 1.4.1-3-g733a5 From 7188706c4fbbae660fa7eb6f2bf13130ddf1726a Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Sat, 20 Jan 2018 14:32:33 -0600 Subject: Teach rustc about DW_AT_noreturn and a few more DIFlags --- src/librustc_llvm/ffi.rs | 4 ++++ src/librustc_trans/debuginfo/mod.rs | 3 +++ src/rustllvm/RustWrapper.cpp | 20 ++++++++++++++++++-- src/test/codegen/noreturnflag.rs | 29 +++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 src/test/codegen/noreturnflag.rs (limited to 'src/test') diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index b97e37f4c8f..8602c559da9 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -498,6 +498,10 @@ pub mod debuginfo { const FlagStaticMember = (1 << 12); const FlagLValueReference = (1 << 13); const FlagRValueReference = (1 << 14); + const FlagExternalTypeRef = (1 << 15); + const FlagIntroducedVirtual = (1 << 18); + const FlagBitField = (1 << 19); + const FlagNoReturn = (1 << 20); const FlagMainSubprogram = (1 << 21); } } diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index b46e12d9d5b..9071eb776d5 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -270,6 +270,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } None => {} }; + if sig.output().is_never() { + flags = flags | DIFlags::FlagNoReturn; + } let fn_metadata = unsafe { llvm::LLVMRustDIBuilderCreateFunction( diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 95130d596e1..2e8207d1cbb 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -457,9 +457,13 @@ enum class LLVMRustDIFlags : uint32_t { FlagStaticMember = (1 << 12), FlagLValueReference = (1 << 13), FlagRValueReference = (1 << 14), - FlagMainSubprogram = (1 << 21), + FlagExternalTypeRef = (1 << 15), + FlagIntroducedVirtual = (1 << 18), + FlagBitField = (1 << 19), + FlagNoReturn = (1 << 20), + FlagMainSubprogram = (1 << 21), // Do not add values that are not supported by the minimum LLVM - // version we support! + // version we support! see llvm/include/llvm/IR/DebugInfoFlags.def }; inline LLVMRustDIFlags operator&(LLVMRustDIFlags A, LLVMRustDIFlags B) { @@ -545,6 +549,18 @@ static unsigned fromRust(LLVMRustDIFlags Flags) { Result |= DINode::DIFlags::FlagRValueReference; } #if LLVM_RUSTLLVM || LLVM_VERSION_GE(4, 0) + if (isSet(Flags & LLVMRustDIFlags::FlagExternalTypeRef)) { + Result |= DINode::DIFlags::FlagExternalTypeRef; + } + if (isSet(Flags & LLVMRustDIFlags::FlagIntroducedVirtual)) { + Result |= DINode::DIFlags::FlagIntroducedVirtual; + } + if (isSet(Flags & LLVMRustDIFlags::FlagBitField)) { + Result |= DINode::DIFlags::FlagBitField; + } + if (isSet(Flags & LLVMRustDIFlags::FlagNoReturn)) { + Result |= DINode::DIFlags::FlagNoReturn; + } if (isSet(Flags & LLVMRustDIFlags::FlagMainSubprogram)) { Result |= DINode::DIFlags::FlagMainSubprogram; } diff --git a/src/test/codegen/noreturnflag.rs b/src/test/codegen/noreturnflag.rs new file mode 100644 index 00000000000..473fed8e046 --- /dev/null +++ b/src/test/codegen/noreturnflag.rs @@ -0,0 +1,29 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength +// min-llvm-version 3.8 + +// compile-flags: -g -C no-prepopulate-passes + +// CHECK-LABEL: foo +// CHECK: {{.*}}DISubprogram{{.*}} name: "foo",{{.*}}DIFlagNoReturn{{.*}} + +#[no_mangle] +pub fn foo() -> ! { + loop {} +} + +// CHECK-LABEL: main +// CHECK: {{.*}}DISubprogram{{.*}}name: "main",{{.*}}DIFlagMainSubprogram{{.*}} + +pub fn main() { + foo(); +} -- cgit 1.4.1-3-g733a5 From f7f6598083f24191bbdb170b993dbf97abd1b5c9 Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Sat, 20 Jan 2018 21:22:11 -0600 Subject: Simplify and fix test --- src/test/codegen/noreturnflag.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src/test') diff --git a/src/test/codegen/noreturnflag.rs b/src/test/codegen/noreturnflag.rs index 473fed8e046..3fa7921b444 100644 --- a/src/test/codegen/noreturnflag.rs +++ b/src/test/codegen/noreturnflag.rs @@ -13,15 +13,12 @@ // compile-flags: -g -C no-prepopulate-passes -// CHECK-LABEL: foo -// CHECK: {{.*}}DISubprogram{{.*}} name: "foo",{{.*}}DIFlagNoReturn{{.*}} +// CHECK: {{.*}}DISubprogram{{.*}}name: "foo"{{.*}}DIFlagNoReturn -#[no_mangle] -pub fn foo() -> ! { +fn foo() -> ! { loop {} } -// CHECK-LABEL: main // CHECK: {{.*}}DISubprogram{{.*}}name: "main",{{.*}}DIFlagMainSubprogram{{.*}} pub fn main() { -- cgit 1.4.1-3-g733a5 From e0f9b26899ea16bb2b6b966266e46698ebad9c4a Mon Sep 17 00:00:00 2001 From: "A.J. Gardner" Date: Sun, 21 Jan 2018 12:36:25 -0600 Subject: Ensure test doesn't run with llvm 3.9 --- src/rustllvm/RustWrapper.cpp | 2 +- src/test/codegen/noreturnflag.rs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'src/test') diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 2e8207d1cbb..42ddf5663f9 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -548,7 +548,6 @@ static unsigned fromRust(LLVMRustDIFlags Flags) { if (isSet(Flags & LLVMRustDIFlags::FlagRValueReference)) { Result |= DINode::DIFlags::FlagRValueReference; } -#if LLVM_RUSTLLVM || LLVM_VERSION_GE(4, 0) if (isSet(Flags & LLVMRustDIFlags::FlagExternalTypeRef)) { Result |= DINode::DIFlags::FlagExternalTypeRef; } @@ -558,6 +557,7 @@ static unsigned fromRust(LLVMRustDIFlags Flags) { 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; } diff --git a/src/test/codegen/noreturnflag.rs b/src/test/codegen/noreturnflag.rs index 3fa7921b444..24a5a4e44cb 100644 --- a/src/test/codegen/noreturnflag.rs +++ b/src/test/codegen/noreturnflag.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// min-llvm-version 3.8 +// min-llvm-version 4.0 // compile-flags: -g -C no-prepopulate-passes @@ -19,8 +19,6 @@ fn foo() -> ! { loop {} } -// CHECK: {{.*}}DISubprogram{{.*}}name: "main",{{.*}}DIFlagMainSubprogram{{.*}} - pub fn main() { foo(); } -- cgit 1.4.1-3-g733a5 From 215d66b998aaa844e2d43ce7cd459c7fa69e0d9f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 22 Jan 2018 17:36:43 -0500 Subject: do not ICE when return type includes unconstrained anon region It turns out that this *can* happen after all, if the region is only used in projections from the input types. --- src/librustc_typeck/astconv.rs | 35 ++++++++++++++++++++--------------- src/test/ui/issue-47511.rs | 35 +++++++++++++++++++++++++++++++++++ src/test/ui/issue-47511.stderr | 16 ++++++++++++++++ 3 files changed, 71 insertions(+), 15 deletions(-) create mode 100644 src/test/ui/issue-47511.rs create mode 100644 src/test/ui/issue-47511.stderr (limited to 'src/test') diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 4616b4cf80c..86deed86405 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1206,22 +1206,27 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let output = bare_fn_ty.output(); let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output); for br in late_bound_in_ret.difference(&late_bound_in_args) { - let br_name = match *br { - ty::BrNamed(_, name) => name, - _ => { - span_bug!( - decl.output.span(), - "anonymous bound region {:?} in return but not args", - br); - } + let lifetime_name = match *br { + ty::BrNamed(_, name) => format!("lifetime `{}`,", name), + ty::BrAnon(_) | ty::BrFresh(_) | ty::BrEnv => format!("an anonymous lifetime"), }; - struct_span_err!(tcx.sess, - decl.output.span(), - E0581, - "return type references lifetime `{}`, \ - which does not appear in the fn input types", - br_name) - .emit(); + let mut err = struct_span_err!(tcx.sess, + decl.output.span(), + E0581, + "return type references {} \ + which is not constrained by the fn input types", + lifetime_name); + if let ty::BrAnon(_) = *br { + // The only way for an anonymous lifetime to wind up + // in the return type but **also** be unconstrained is + // if it only appears in "associated types" in the + // input. See #47511 for an example. In this case, + // though we can easily give a hint that ought to be + // relevant. + err.note("lifetimes appearing in an associated type \ + are not considered constrained"); + } + err.emit(); } bare_fn_ty diff --git a/src/test/ui/issue-47511.rs b/src/test/ui/issue-47511.rs new file mode 100644 index 00000000000..df4ff301bc9 --- /dev/null +++ b/src/test/ui/issue-47511.rs @@ -0,0 +1,35 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #47511: anonymous lifetimes can appear +// unconstrained in a return type, but only if they appear just once +// in the input, as the input to a projection. + +fn f(_: X) -> X { + //~^ ERROR return type references an anonymous lifetime + unimplemented!() +} + +fn g<'a>(_: X<'a>) -> X<'a> { + //~^ ERROR return type references lifetime `'a`, which is not constrained + unimplemented!() +} + +type X<'a> = <&'a () as Trait>::Value; + +trait Trait { + type Value; +} + +impl<'a> Trait for &'a () { + type Value = (); +} + +fn main() {} diff --git a/src/test/ui/issue-47511.stderr b/src/test/ui/issue-47511.stderr new file mode 100644 index 00000000000..fabd6b6c253 --- /dev/null +++ b/src/test/ui/issue-47511.stderr @@ -0,0 +1,16 @@ +error[E0581]: return type references an anonymous lifetime which is not constrained by the fn input types + --> $DIR/issue-47511.rs:15:15 + | +15 | fn f(_: X) -> X { + | ^ + | + = note: lifetimes appearing in an associated type are not considered constrained + +error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types + --> $DIR/issue-47511.rs:20:23 + | +20 | fn g<'a>(_: X<'a>) -> X<'a> { + | ^^^^^ + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From e76d3f62cc34a77496305639f22a7da168ebc301 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Sun, 21 Jan 2018 19:19:07 -0800 Subject: Fix test for variadic error change --- src/librustc/session/config.rs | 2 +- src/test/ui/variadic-ffi-3.stderr | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'src/test') diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index e30a43d3d1a..4d54f2a3677 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1626,7 +1626,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) } if !debugging_opts.unstable_options && debugging_opts.explain { - early_error(ErrorOutputType::Json(false), "-Z --explain is unstable"); + early_error(error_format, "-Z --explain is unstable"); } let mut output_types = BTreeMap::new(); diff --git a/src/test/ui/variadic-ffi-3.stderr b/src/test/ui/variadic-ffi-3.stderr index be158c1e398..1bf3798b95a 100644 --- a/src/test/ui/variadic-ffi-3.stderr +++ b/src/test/ui/variadic-ffi-3.stderr @@ -34,41 +34,41 @@ error[E0308]: mismatched types = note: expected type `extern "C" fn(isize, u8, ...)` found type `extern "C" fn(isize, u8) {bar}` -error[E0617]: can't pass `f32` to variadic function, cast to `c_double` +error[E0617]: can't pass `f32` to variadic function --> $DIR/variadic-ffi-3.rs:34:19 | 34 | foo(1, 2, 3f32); //~ ERROR can't pass `f32` to variadic function, cast to `c_double` - | ^^^^ + | ^^^^ help: cast the value to `c_double`: `3f32 as c_double` -error[E0617]: can't pass `bool` to variadic function, cast to `c_int` +error[E0617]: can't pass `bool` to variadic function --> $DIR/variadic-ffi-3.rs:35:19 | 35 | foo(1, 2, true); //~ ERROR can't pass `bool` to variadic function, cast to `c_int` - | ^^^^ + | ^^^^ help: cast the value to `c_int`: `true as c_int` -error[E0617]: can't pass `i8` to variadic function, cast to `c_int` +error[E0617]: can't pass `i8` to variadic function --> $DIR/variadic-ffi-3.rs:36:19 | 36 | foo(1, 2, 1i8); //~ ERROR can't pass `i8` to variadic function, cast to `c_int` - | ^^^ + | ^^^ help: cast the value to `c_int`: `1i8 as c_int` -error[E0617]: can't pass `u8` to variadic function, cast to `c_uint` +error[E0617]: can't pass `u8` to variadic function --> $DIR/variadic-ffi-3.rs:37:19 | 37 | foo(1, 2, 1u8); //~ ERROR can't pass `u8` to variadic function, cast to `c_uint` - | ^^^ + | ^^^ help: cast the value to `c_uint`: `1u8 as c_uint` -error[E0617]: can't pass `i16` to variadic function, cast to `c_int` +error[E0617]: can't pass `i16` to variadic function --> $DIR/variadic-ffi-3.rs:38:19 | 38 | foo(1, 2, 1i16); //~ ERROR can't pass `i16` to variadic function, cast to `c_int` - | ^^^^ + | ^^^^ help: cast the value to `c_int`: `1i16 as c_int` -error[E0617]: can't pass `u16` to variadic function, cast to `c_uint` +error[E0617]: can't pass `u16` to variadic function --> $DIR/variadic-ffi-3.rs:39:19 | 39 | foo(1, 2, 1u16); //~ ERROR can't pass `u16` to variadic function, cast to `c_uint` - | ^^^^ + | ^^^^ help: cast the value to `c_uint`: `1u16 as c_uint` error: aborting due to 10 previous errors -- cgit 1.4.1-3-g733a5 From ffb827aff3340f8e6e012fd4a302616ddcf855fa Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Mon, 22 Jan 2018 08:35:21 -0800 Subject: Fix test redux --- src/librustc_typeck/check/cast.rs | 16 ++++++++-------- src/test/compile-fail/E0617.rs | 18 ++++++++++++------ src/test/compile-fail/issue-32201.rs | 3 ++- src/test/ui/variadic-ffi-3.rs | 12 ++++++------ src/test/ui/variadic-ffi-3.stderr | 12 ++++++------ 5 files changed, 34 insertions(+), 27 deletions(-) (limited to 'src/test') diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 3cd93a1c845..334e1b06e37 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -293,7 +293,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> { if fcx.tcx.sess.opts.debugging_opts.explain && !fcx.tcx.sess.parse_sess.span_diagnostic .code_emitted(&err.get_code().unwrap()) { - err.note( + err.help( "Thin pointers are \"simple\" pointers: they are purely a reference to a memory address. @@ -301,13 +301,13 @@ Fat pointers are pointers referencing \"Dynamically Sized Types\" (also called DST). DST don't have a statically known size, therefore they can only exist behind some kind of pointers that contain additional information. Slices and trait objects are DSTs. In the case of slices, -the additional information the fat pointer holds is their size."); - err.note("to fix this error, don't try to cast directly between thin and fat \ - pointers"); - err.help("for more information about casts, take a look at - [The Book]\ - (https://doc.rust-lang.org/book/first-edition/\ - casting-between-types.html)"); +the additional information the fat pointer holds is their size. + +To fix this error, don't try to cast directly between thin and fat +pointers. + +For more information about casts, take a look at The Book: +https://doc.rust-lang.org/book/first-edition/casting-between-types.html"); } err.emit(); } diff --git a/src/test/compile-fail/E0617.rs b/src/test/compile-fail/E0617.rs index 7b769ff4ae2..9375fd9cade 100644 --- a/src/test/compile-fail/E0617.rs +++ b/src/test/compile-fail/E0617.rs @@ -17,16 +17,22 @@ extern { fn main() { unsafe { printf(::std::ptr::null(), 0f32); - //~^ ERROR can't pass `f32` to variadic function, cast to `c_double` [E0617] + //~^ ERROR can't pass `f32` to variadic function + //~| HELP cast the value to `c_double` printf(::std::ptr::null(), 0i8); - //~^ ERROR can't pass `i8` to variadic function, cast to `c_int` [E0617] + //~^ ERROR can't pass `i8` to variadic function + //~| HELP cast the value to `c_int` printf(::std::ptr::null(), 0i16); - //~^ ERROR can't pass `i16` to variadic function, cast to `c_int` [E0617] + //~^ ERROR can't pass `i16` to variadic function + //~| HELP cast the value to `c_int` printf(::std::ptr::null(), 0u8); - //~^ ERROR can't pass `u8` to variadic function, cast to `c_uint` [E0617] + //~^ ERROR can't pass `u8` to variadic function + //~| HELP cast the value to `c_uint` printf(::std::ptr::null(), 0u16); - //~^ ERROR can't pass `u16` to variadic function, cast to `c_uint` [E0617] + //~^ ERROR can't pass `u16` to variadic function + //~| HELP cast the value to `c_uint` printf(::std::ptr::null(), printf); - //~^ ERROR can't pass `unsafe extern "C" fn(*const i8, ...) {printf}` to variadic function, cast to `unsafe extern "C" fn(*const i8, ...)` [E0617] + //~^ ERROR can't pass `unsafe extern "C" fn(*const i8, ...) {printf}` to variadic function + //~| HELP cast the value to `unsafe extern "C" fn(*const i8, ...)` } } diff --git a/src/test/compile-fail/issue-32201.rs b/src/test/compile-fail/issue-32201.rs index bcc53df68a3..bf9f8ecbc80 100644 --- a/src/test/compile-fail/issue-32201.rs +++ b/src/test/compile-fail/issue-32201.rs @@ -17,6 +17,7 @@ fn bar(_: *const u8) {} fn main() { unsafe { foo(0, bar); - //~^ ERROR can't pass `fn(*const u8) {bar}` to variadic function, cast to `fn(*const u8)` + //~^ ERROR can't pass `fn(*const u8) {bar}` to variadic function + //~| HELP cast the value to `fn(*const u8)` } } diff --git a/src/test/ui/variadic-ffi-3.rs b/src/test/ui/variadic-ffi-3.rs index 12beebc181b..9807952c636 100644 --- a/src/test/ui/variadic-ffi-3.rs +++ b/src/test/ui/variadic-ffi-3.rs @@ -31,11 +31,11 @@ fn main() { //~| expected type `extern "C" fn(isize, u8, ...)` //~| found type `extern "C" fn(isize, u8) {bar}` - foo(1, 2, 3f32); //~ ERROR can't pass `f32` to variadic function, cast to `c_double` - foo(1, 2, true); //~ ERROR can't pass `bool` to variadic function, cast to `c_int` - foo(1, 2, 1i8); //~ ERROR can't pass `i8` to variadic function, cast to `c_int` - foo(1, 2, 1u8); //~ ERROR can't pass `u8` to variadic function, cast to `c_uint` - foo(1, 2, 1i16); //~ ERROR can't pass `i16` to variadic function, cast to `c_int` - foo(1, 2, 1u16); //~ ERROR can't pass `u16` to variadic function, cast to `c_uint` + foo(1, 2, 3f32); //~ ERROR can't pass `f32` to variadic function + foo(1, 2, true); //~ ERROR can't pass `bool` to variadic function + foo(1, 2, 1i8); //~ ERROR can't pass `i8` to variadic function + foo(1, 2, 1u8); //~ ERROR can't pass `u8` to variadic function + foo(1, 2, 1i16); //~ ERROR can't pass `i16` to variadic function + foo(1, 2, 1u16); //~ ERROR can't pass `u16` to variadic function } } diff --git a/src/test/ui/variadic-ffi-3.stderr b/src/test/ui/variadic-ffi-3.stderr index 1bf3798b95a..54275fbc4f2 100644 --- a/src/test/ui/variadic-ffi-3.stderr +++ b/src/test/ui/variadic-ffi-3.stderr @@ -37,37 +37,37 @@ error[E0308]: mismatched types error[E0617]: can't pass `f32` to variadic function --> $DIR/variadic-ffi-3.rs:34:19 | -34 | foo(1, 2, 3f32); //~ ERROR can't pass `f32` to variadic function, cast to `c_double` +34 | foo(1, 2, 3f32); //~ ERROR can't pass `f32` to variadic function | ^^^^ help: cast the value to `c_double`: `3f32 as c_double` error[E0617]: can't pass `bool` to variadic function --> $DIR/variadic-ffi-3.rs:35:19 | -35 | foo(1, 2, true); //~ ERROR can't pass `bool` to variadic function, cast to `c_int` +35 | foo(1, 2, true); //~ ERROR can't pass `bool` to variadic function | ^^^^ help: cast the value to `c_int`: `true as c_int` error[E0617]: can't pass `i8` to variadic function --> $DIR/variadic-ffi-3.rs:36:19 | -36 | foo(1, 2, 1i8); //~ ERROR can't pass `i8` to variadic function, cast to `c_int` +36 | foo(1, 2, 1i8); //~ ERROR can't pass `i8` to variadic function | ^^^ help: cast the value to `c_int`: `1i8 as c_int` error[E0617]: can't pass `u8` to variadic function --> $DIR/variadic-ffi-3.rs:37:19 | -37 | foo(1, 2, 1u8); //~ ERROR can't pass `u8` to variadic function, cast to `c_uint` +37 | foo(1, 2, 1u8); //~ ERROR can't pass `u8` to variadic function | ^^^ help: cast the value to `c_uint`: `1u8 as c_uint` error[E0617]: can't pass `i16` to variadic function --> $DIR/variadic-ffi-3.rs:38:19 | -38 | foo(1, 2, 1i16); //~ ERROR can't pass `i16` to variadic function, cast to `c_int` +38 | foo(1, 2, 1i16); //~ ERROR can't pass `i16` to variadic function | ^^^^ help: cast the value to `c_int`: `1i16 as c_int` error[E0617]: can't pass `u16` to variadic function --> $DIR/variadic-ffi-3.rs:39:19 | -39 | foo(1, 2, 1u16); //~ ERROR can't pass `u16` to variadic function, cast to `c_uint` +39 | foo(1, 2, 1u16); //~ ERROR can't pass `u16` to variadic function | ^^^^ help: cast the value to `c_uint`: `1u16 as c_uint` error: aborting due to 10 previous errors -- cgit 1.4.1-3-g733a5 From 2e81ce7dfa1c3429ee82f336bbec59e056702b3d Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Tue, 23 Jan 2018 04:22:20 +0000 Subject: rustdoc: Hide methods from #[doc(masked)] crates from the search index --- src/librustdoc/html/render.rs | 52 +++++++++++++++++++----------------- src/test/rustdoc/auxiliary/masked.rs | 20 ++++++++++++++ src/test/rustdoc/masked.rs | 40 +++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 25 deletions(-) create mode 100644 src/test/rustdoc/auxiliary/masked.rs create mode 100644 src/test/rustdoc/masked.rs (limited to 'src/test') diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index cfa09ea30a8..dd40f979fd1 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1174,6 +1174,16 @@ impl DocFolder for Cache { _ => self.stripped_mod, }; + // If the impl is from a masked crate or references something from a + // masked crate then remove it completely. + if let clean::ImplItem(ref i) = item.inner { + if self.masked_crates.contains(&item.def_id.krate) || + i.trait_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) || + i.for_.def_id().map_or(false, |d| self.masked_crates.contains(&d.krate)) { + return None; + } + } + // Register any generics to their corresponding string. This is used // when pretty-printing types. if let Some(generics) = item.inner.generics() { @@ -1188,14 +1198,10 @@ impl DocFolder for Cache { // Collect all the implementors of traits. if let clean::ImplItem(ref i) = item.inner { - if !self.masked_crates.contains(&item.def_id.krate) { - if let Some(did) = i.trait_.def_id() { - if i.for_.def_id().map_or(true, |d| !self.masked_crates.contains(&d.krate)) { - self.implementors.entry(did).or_insert(vec![]).push(Impl { - impl_item: item.clone(), - }); - } - } + if let Some(did) = i.trait_.def_id() { + self.implementors.entry(did).or_insert(vec![]).push(Impl { + impl_item: item.clone(), + }); } } @@ -1358,24 +1364,20 @@ impl DocFolder for Cache { // Note: matching twice to restrict the lifetime of the `i` borrow. let mut dids = FxHashSet(); if let clean::Item { inner: clean::ImplItem(ref i), .. } = item { - let masked_trait = i.trait_.def_id().map_or(false, - |d| self.masked_crates.contains(&d.krate)); - if !masked_trait { - match i.for_ { - clean::ResolvedPath { did, .. } | - clean::BorrowedRef { - type_: box clean::ResolvedPath { did, .. }, .. - } => { - dids.insert(did); - } - ref t => { - let did = t.primitive_type().and_then(|t| { - self.primitive_locations.get(&t).cloned() - }); + match i.for_ { + clean::ResolvedPath { did, .. } | + clean::BorrowedRef { + type_: box clean::ResolvedPath { did, .. }, .. + } => { + dids.insert(did); + } + ref t => { + let did = t.primitive_type().and_then(|t| { + self.primitive_locations.get(&t).cloned() + }); - if let Some(did) = did { - dids.insert(did); - } + if let Some(did) = did { + dids.insert(did); } } } diff --git a/src/test/rustdoc/auxiliary/masked.rs b/src/test/rustdoc/auxiliary/masked.rs new file mode 100644 index 00000000000..e0d53a72220 --- /dev/null +++ b/src/test/rustdoc/auxiliary/masked.rs @@ -0,0 +1,20 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[derive(Clone)] +pub struct MaskedStruct; + +pub trait MaskedTrait { + fn masked_method(); +} + +impl MaskedTrait for String { + fn masked_method() {} +} diff --git a/src/test/rustdoc/masked.rs b/src/test/rustdoc/masked.rs new file mode 100644 index 00000000000..1f398da84e5 --- /dev/null +++ b/src/test/rustdoc/masked.rs @@ -0,0 +1,40 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:masked.rs + +#![feature(doc_masked)] + +#![crate_name = "foo"] + +#[doc(masked)] +extern crate masked; + +// @!has 'search-index.js' 'masked_method' + +// @!has 'foo/struct.String.html' 'MaskedTrait' +// @!has 'foo/struct.String.html' 'masked_method' +pub use std::string::String; + +// @!has 'foo/trait.Clone.html' 'MaskedStruct' +pub use std::clone::Clone; + +// @!has 'foo/struct.MyStruct.html' 'MaskedTrait' +// @!has 'foo/struct.MyStruct.html' 'masked_method' +pub struct MyStruct; + +impl masked::MaskedTrait for MyStruct { + fn masked_method() {} +} + +// @!has 'foo/trait.MyTrait.html' 'MaskedStruct' +pub trait MyTrait {} + +impl MyTrait for masked::MaskedStruct {} -- cgit 1.4.1-3-g733a5 From 8bde2acfc7876148ebfe192780434dbb969eded3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 16 Jan 2018 15:02:31 -0800 Subject: rustc: Add `-C lto=val` option This commit primarily adds the ability to control what kind of LTO happens when rustc performs LTO, namely allowing values to be specified to the `-C lto` option, such as `-C lto=thin` and `-C lto=fat`. (where "fat" is the previous kind of LTO, throw everything in one giant module) Along the way this also refactors a number of fields which store information about whether LTO/ThinLTO are enabled to unify them all into one field through which everything is dispatched, hopefully removing a number of special cases throughout. This is intended to help mitigate #47409 but will require a backport as well, and this would unfortunately need to be an otherwise insta-stable option. --- src/librustc/session/config.rs | 56 ++++++++++--- src/librustc/session/mod.rs | 92 ++++++++++++++-------- src/librustc_trans/back/link.rs | 22 ++++-- src/librustc_trans/back/lto.rs | 36 ++++----- src/librustc_trans/back/write.rs | 88 +++++++++++---------- src/test/run-make/codegen-options-parsing/Makefile | 6 +- src/test/run-pass/fat-lto.rs | 17 ++++ src/test/run-pass/thinlto/all-crates.rs | 17 ++++ src/test/run-pass/thinlto/thin-lto-inlines2.rs | 2 +- 9 files changed, 221 insertions(+), 115 deletions(-) create mode 100644 src/test/run-pass/fat-lto.rs create mode 100644 src/test/run-pass/thinlto/all-crates.rs (limited to 'src/test') diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index da119ba4569..3fac9ce41f1 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -72,6 +72,26 @@ pub enum OptLevel { SizeMin, // -Oz } +#[derive(Clone, Copy, PartialEq, Hash)] +pub enum Lto { + /// Don't do any LTO whatsoever + No, + + /// Do a full crate graph LTO. The flavor is determined by the compiler + /// (currently the default is "fat"). + Yes, + + /// Do a full crate graph LTO with ThinLTO + Thin, + + /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen + /// units). + ThinLocal, + + /// Do a full crate graph LTO with "fat" LTO + Fat, +} + #[derive(Clone, Copy, PartialEq, Hash)] pub enum DebugInfoLevel { NoDebugInfo, @@ -389,7 +409,7 @@ top_level_options!( // commands like `--emit llvm-ir` which they're often incompatible with // if we otherwise use the defaults of rustc. cli_forced_codegen_units: Option [UNTRACKED], - cli_forced_thinlto: Option [UNTRACKED], + cli_forced_thinlto_off: bool [UNTRACKED], } ); @@ -590,7 +610,7 @@ pub fn basic_options() -> Options { debug_assertions: true, actually_rustdoc: false, cli_forced_codegen_units: None, - cli_forced_thinlto: None, + cli_forced_thinlto_off: false, } } @@ -780,11 +800,13 @@ macro_rules! options { Some("crate=integer"); pub const parse_unpretty: Option<&'static str> = Some("`string` or `string=string`"); + pub const parse_lto: Option<&'static str> = + Some("one of `thin`, `fat`, or omitted"); } #[allow(dead_code)] mod $mod_set { - use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer}; + use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto}; use rustc_back::{LinkerFlavor, PanicStrategy, RelroLevel}; use std::path::PathBuf; @@ -978,6 +1000,16 @@ macro_rules! options { _ => false, } } + + fn parse_lto(slot: &mut Lto, v: Option<&str>) -> bool { + *slot = match v { + None => Lto::Yes, + Some("thin") => Lto::Thin, + Some("fat") => Lto::Fat, + Some(_) => return false, + }; + true + } } ) } @@ -994,7 +1026,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, "extra arguments to append to the linker invocation (space separated)"), link_dead_code: bool = (false, parse_bool, [UNTRACKED], "don't let linker strip dead code (turning it on can be used for code coverage)"), - lto: bool = (false, parse_bool, [TRACKED], + lto: Lto = (Lto::No, parse_lto, [TRACKED], "perform LLVM link-time optimizations"), target_cpu: Option = (None, parse_opt_string, [TRACKED], "select target processor (rustc --print target-cpus for details)"), @@ -1677,7 +1709,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) let mut cg = build_codegen_options(matches, error_format); let mut codegen_units = cg.codegen_units; - let mut thinlto = None; + let mut disable_thinlto = false; // Issue #30063: if user requests llvm-related output to one // particular path, disable codegen-units. @@ -1699,12 +1731,12 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) } early_warn(error_format, "resetting to default -C codegen-units=1"); codegen_units = Some(1); - thinlto = Some(false); + disable_thinlto = true; } } _ => { codegen_units = Some(1); - thinlto = Some(false); + disable_thinlto = true; } } } @@ -1734,7 +1766,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) (&None, &None) => None, }.map(|m| PathBuf::from(m)); - if cg.lto && incremental.is_some() { + if cg.lto != Lto::No && incremental.is_some() { early_error(error_format, "can't perform LTO when compiling incrementally"); } @@ -1934,7 +1966,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) debug_assertions, actually_rustdoc: false, cli_forced_codegen_units: codegen_units, - cli_forced_thinlto: thinlto, + cli_forced_thinlto_off: disable_thinlto, }, cfg) } @@ -2052,7 +2084,7 @@ mod dep_tracking { use std::hash::Hash; use std::path::PathBuf; use std::collections::hash_map::DefaultHasher; - use super::{Passes, CrateType, OptLevel, DebugInfoLevel, + use super::{Passes, CrateType, OptLevel, DebugInfoLevel, Lto, OutputTypes, Externs, ErrorOutputType, Sanitizer}; use syntax::feature_gate::UnstableFeatures; use rustc_back::{PanicStrategy, RelroLevel}; @@ -2107,6 +2139,7 @@ mod dep_tracking { impl_dep_tracking_hash_via_hash!(RelroLevel); impl_dep_tracking_hash_via_hash!(Passes); impl_dep_tracking_hash_via_hash!(OptLevel); + impl_dep_tracking_hash_via_hash!(Lto); impl_dep_tracking_hash_via_hash!(DebugInfoLevel); impl_dep_tracking_hash_via_hash!(UnstableFeatures); impl_dep_tracking_hash_via_hash!(Externs); @@ -2180,6 +2213,7 @@ mod tests { use lint; use middle::cstore; use session::config::{build_configuration, build_session_options_and_crate_config}; + use session::config::Lto; use session::build_session; use std::collections::{BTreeMap, BTreeSet}; use std::iter::FromIterator; @@ -2656,7 +2690,7 @@ mod tests { // Make sure changing a [TRACKED] option changes the hash opts = reference.clone(); - opts.cg.lto = true; + opts.cg.lto = Lto::Fat; assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 36f716a4a76..02cd6a92eb7 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -498,9 +498,65 @@ impl Session { self.use_mir() } - pub fn lto(&self) -> bool { - self.opts.cg.lto || self.target.target.options.requires_lto + /// Calculates the flavor of LTO to use for this compilation. + pub fn lto(&self) -> config::Lto { + // If our target has codegen requirements ignore the command line + if self.target.target.options.requires_lto { + return config::Lto::Fat + } + + // If the user specified something, return that. If they only said `-C + // lto` and we've for whatever reason forced off ThinLTO via the CLI, + // then ensure we can't use a ThinLTO. + match self.opts.cg.lto { + config::Lto::No => {} + config::Lto::Yes if self.opts.cli_forced_thinlto_off => { + return config::Lto::Fat + } + other => return other, + } + + // Ok at this point the target doesn't require anything and the user + // hasn't asked for anything. Our next decision is whether or not + // we enable "auto" ThinLTO where we use multiple codegen units and + // then do ThinLTO over those codegen units. The logic below will + // either return `No` or `ThinLocal`. + + // If processing command line options determined that we're incompatible + // with ThinLTO (e.g. `-C lto --emit llvm-ir`) then return that option. + if self.opts.cli_forced_thinlto_off { + return config::Lto::No + } + + // If `-Z thinlto` specified process that, but note that this is mostly + // a deprecated option now that `-C lto=thin` exists. + if let Some(enabled) = self.opts.debugging_opts.thinlto { + if enabled { + return config::Lto::ThinLocal + } else { + return config::Lto::No + } + } + + // If there's only one codegen unit and LTO isn't enabled then there's + // no need for ThinLTO so just return false. + if self.codegen_units() == 1 { + return config::Lto::No + } + + // Right now ThinLTO isn't compatible with incremental compilation. + if self.opts.incremental.is_some() { + return config::Lto::No + } + + // Now we're in "defaults" territory. By default we enable ThinLTO for + // optimized compiles (anything greater than O0). + match self.opts.optimize { + config::OptLevel::No => config::Lto::No, + _ => config::Lto::ThinLocal, + } } + /// Returns the panic strategy for this compile session. If the user explicitly selected one /// using '-C panic', use that, otherwise use the panic strategy defined by the target. pub fn panic_strategy(&self) -> PanicStrategy { @@ -804,38 +860,6 @@ impl Session { // scientific. 16 } - - /// Returns whether ThinLTO is enabled for this compilation - pub fn thinlto(&self) -> bool { - // If processing command line options determined that we're incompatible - // with ThinLTO (e.g. `-C lto --emit llvm-ir`) then return that option. - if let Some(enabled) = self.opts.cli_forced_thinlto { - return enabled - } - - // If explicitly specified, use that with the next highest priority - if let Some(enabled) = self.opts.debugging_opts.thinlto { - return enabled - } - - // If there's only one codegen unit and LTO isn't enabled then there's - // no need for ThinLTO so just return false. - if self.codegen_units() == 1 && !self.lto() { - return false - } - - // Right now ThinLTO isn't compatible with incremental compilation. - if self.opts.incremental.is_some() { - return false - } - - // Now we're in "defaults" territory. By default we enable ThinLTO for - // optimized compiles (anything greater than O0). - match self.opts.optimize { - config::OptLevel::No => false, - _ => true, - } - } } pub fn build_session(sopts: config::Options, diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 923e5549927..f050edcd513 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -16,7 +16,7 @@ use super::rpath::RPathConfig; use super::rpath; use metadata::METADATA_FILENAME; use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType, PrintRequest}; -use rustc::session::config::RUST_CGU_EXT; +use rustc::session::config::{RUST_CGU_EXT, Lto}; use rustc::session::filesearch; use rustc::session::search_paths::PathKind; use rustc::session::Session; @@ -503,7 +503,8 @@ fn link_staticlib(sess: &Session, }); ab.add_rlib(path, &name.as_str(), - sess.lto() && !ignored_for_lto(sess, &trans.crate_info, cnum), + is_full_lto_enabled(sess) && + !ignored_for_lto(sess, &trans.crate_info, cnum), skip_object_files).unwrap(); all_native_libs.extend(trans.crate_info.native_libraries[&cnum].iter().cloned()); @@ -1211,7 +1212,8 @@ fn add_upstream_rust_crates(cmd: &mut Linker, lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) }); - if (!sess.lto() || ignored_for_lto(sess, &trans.crate_info, cnum)) && + if (!is_full_lto_enabled(sess) || + ignored_for_lto(sess, &trans.crate_info, cnum)) && crate_type != config::CrateTypeDylib && !skip_native { cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); @@ -1264,7 +1266,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // file, then we don't need the object file as it's part of the // LTO module. Note that `#![no_builtins]` is excluded from LTO, // though, so we let that object file slide. - let skip_because_lto = sess.lto() && + let skip_because_lto = is_full_lto_enabled(sess) && is_rust_object && (sess.target.target.options.no_builtins || !trans.crate_info.is_no_builtins.contains(&cnum)); @@ -1301,7 +1303,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, fn add_dynamic_crate(cmd: &mut Linker, sess: &Session, cratepath: &Path) { // If we're performing LTO, then it should have been previously required // that all upstream rust dependencies were available in an rlib format. - assert!(!sess.lto()); + assert!(!is_full_lto_enabled(sess)); // Just need to tell the linker about where the library lives and // what its name is @@ -1409,3 +1411,13 @@ fn link_binaryen(sess: &Session, e)); } } + +fn is_full_lto_enabled(sess: &Session) -> bool { + match sess.lto() { + Lto::Yes | + Lto::Thin | + Lto::Fat => true, + Lto::No | + Lto::ThinLocal => false, + } +} diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index b612247ffcd..9ff5bcf7a33 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -18,7 +18,7 @@ use llvm::{ModuleRef, TargetMachineRef, True, False}; use llvm; use rustc::hir::def_id::LOCAL_CRATE; use rustc::middle::exported_symbols::SymbolExportLevel; -use rustc::session::config; +use rustc::session::config::{self, Lto}; use rustc::util::common::time; use time_graph::Timeline; use {ModuleTranslation, ModuleLlvm, ModuleKind, ModuleSource}; @@ -95,25 +95,22 @@ impl LtoModuleTranslation { } } -pub enum LTOMode { - WholeCrateGraph, - JustThisCrate, -} - pub(crate) fn run(cgcx: &CodegenContext, - modules: Vec, - mode: LTOMode, - timeline: &mut Timeline) + modules: Vec, + timeline: &mut Timeline) -> Result, FatalError> { let diag_handler = cgcx.create_diag_handler(); - let export_threshold = match mode { - LTOMode::WholeCrateGraph => { + let export_threshold = match cgcx.lto { + // We're just doing LTO for our one crate + Lto::ThinLocal => SymbolExportLevel::Rust, + + // We're doing LTO for the entire crate graph + Lto::Yes | Lto::Fat | Lto::Thin => { symbol_export::crates_export_threshold(&cgcx.crate_types) } - LTOMode::JustThisCrate => { - SymbolExportLevel::Rust - } + + Lto::No => panic!("didn't request LTO but we're doing LTO"), }; let symbol_filter = &|&(ref name, _, level): &(String, _, SymbolExportLevel)| { @@ -140,7 +137,7 @@ pub(crate) fn run(cgcx: &CodegenContext, // We save off all the bytecode and LLVM module ids for later processing // with either fat or thin LTO let mut upstream_modules = Vec::new(); - if let LTOMode::WholeCrateGraph = mode { + if cgcx.lto != Lto::ThinLocal { if cgcx.opts.cg.prefer_dynamic { diag_handler.struct_err("cannot prefer dynamic linking when performing LTO") .note("only 'staticlib', 'bin', and 'cdylib' outputs are \ @@ -186,13 +183,16 @@ pub(crate) fn run(cgcx: &CodegenContext, } let arr = symbol_white_list.iter().map(|c| c.as_ptr()).collect::>(); - match mode { - LTOMode::WholeCrateGraph if !cgcx.thinlto => { + match cgcx.lto { + Lto::Yes | // `-C lto` == fat LTO by default + Lto::Fat => { fat_lto(cgcx, &diag_handler, modules, upstream_modules, &arr, timeline) } - _ => { + Lto::Thin | + Lto::ThinLocal => { thin_lto(&diag_handler, modules, upstream_modules, &arr, timeline) } + Lto::No => unreachable!(), } } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index a013af7a460..a4af080ebf7 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -19,7 +19,7 @@ use rustc_incremental::{save_trans_partition, in_incr_comp_dir}; use rustc::dep_graph::{DepGraph, WorkProductFileKind}; use rustc::middle::cstore::{LinkMeta, EncodedMetadata}; use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses, - AllPasses, Sanitizer}; + AllPasses, Sanitizer, Lto}; use rustc::session::Session; use rustc::util::nodemap::FxHashMap; use rustc_back::LinkerFlavor; @@ -318,8 +318,7 @@ impl ModuleConfig { pub struct CodegenContext { // Resouces needed when running LTO pub time_passes: bool, - pub lto: bool, - pub thinlto: bool, + pub lto: Lto, pub no_landing_pads: bool, pub save_temps: bool, pub fewer_names: bool, @@ -576,12 +575,7 @@ fn generate_lto_work(cgcx: &CodegenContext, TRANS_WORK_PACKAGE_KIND, "generate lto") }).unwrap_or(Timeline::noop()); - let mode = if cgcx.lto { - lto::LTOMode::WholeCrateGraph - } else { - lto::LTOMode::JustThisCrate - }; - let lto_modules = lto::run(cgcx, modules, mode, &mut timeline) + let lto_modules = lto::run(cgcx, modules, &mut timeline) .unwrap_or_else(|e| panic!(e)); lto_modules.into_iter().map(|module| { @@ -1280,28 +1274,51 @@ fn execute_work_item(cgcx: &CodegenContext, unsafe { optimize(cgcx, &diag_handler, &mtrans, config, timeline)?; - let lto = cgcx.lto; + // After we've done the initial round of optimizations we need to + // decide whether to synchronously codegen this module or ship it + // back to the coordinator thread for further LTO processing (which + // has to wait for all the initial modules to be optimized). + // + // Here we dispatch based on the `cgcx.lto` and kind of module we're + // translating... + let needs_lto = match cgcx.lto { + Lto::No => false, + + // Here we've got a full crate graph LTO requested. We ignore + // this, however, if the crate type is only an rlib as there's + // no full crate graph to process, that'll happen later. + // + // This use case currently comes up primarily for targets that + // require LTO so the request for LTO is always unconditionally + // passed down to the backend, but we don't actually want to do + // anything about it yet until we've got a final product. + Lto::Yes | Lto::Fat | Lto::Thin => { + cgcx.crate_types.len() != 1 || + cgcx.crate_types[0] != config::CrateTypeRlib + } - let auto_thin_lto = - cgcx.thinlto && - cgcx.total_cgus > 1 && - mtrans.kind != ModuleKind::Allocator; + // When we're automatically doing ThinLTO for multi-codegen-unit + // builds we don't actually want to LTO the allocator modules if + // it shows up. This is due to various linker shenanigans that + // we'll encounter later. + // + // Additionally here's where we also factor in the current LLVM + // version. If it doesn't support ThinLTO we skip this. + Lto::ThinLocal => { + mtrans.kind != ModuleKind::Allocator && + llvm::LLVMRustThinLTOAvailable() + } + }; - // If we're a metadata module we never participate in LTO. - // - // If LTO was explicitly requested on the command line, we always - // LTO everything else. - // - // If LTO *wasn't* explicitly requested and we're not a metdata - // module, then we may automatically do ThinLTO if we've got - // multiple codegen units. Note, however, that the allocator module - // doesn't participate here automatically because of linker - // shenanigans later on. - if mtrans.kind == ModuleKind::Metadata || (!lto && !auto_thin_lto) { + // Metadata modules never participate in LTO regardless of the lto + // settings. + let needs_lto = needs_lto && mtrans.kind != ModuleKind::Metadata; + + if needs_lto { + Ok(WorkItemResult::NeedsLTO(mtrans)) + } else { let module = codegen(cgcx, &diag_handler, mtrans, config, timeline)?; Ok(WorkItemResult::Compiled(module)) - } else { - Ok(WorkItemResult::NeedsLTO(mtrans)) } } } @@ -1377,28 +1394,13 @@ fn start_executing_work(tcx: TyCtxt, each_linked_rlib_for_lto.push((cnum, path.to_path_buf())); })); - let crate_types = sess.crate_types.borrow(); - let only_rlib = crate_types.len() == 1 && - crate_types[0] == config::CrateTypeRlib; - let wasm_import_memory = attr::contains_name(&tcx.hir.krate().attrs, "wasm_import_memory"); let cgcx = CodegenContext { crate_types: sess.crate_types.borrow().clone(), each_linked_rlib_for_lto, - // If we're only building an rlibc then allow the LTO flag to be passed - // but don't actually do anything, the full LTO will happen later - lto: sess.lto() && !only_rlib, - - // Enable ThinLTO if requested, but only if the target we're compiling - // for doesn't require full LTO. Some targets require one LLVM module - // (they effectively don't have a linker) so it's up to us to use LTO to - // link everything together. - thinlto: sess.thinlto() && - !sess.target.target.options.requires_lto && - unsafe { llvm::LLVMRustThinLTOAvailable() }, - + lto: sess.lto(), no_landing_pads: sess.no_landing_pads(), fewer_names: sess.fewer_names(), save_temps: sess.opts.cg.save_temps, diff --git a/src/test/run-make/codegen-options-parsing/Makefile b/src/test/run-make/codegen-options-parsing/Makefile index 81e06043c87..fda96a8b1fb 100644 --- a/src/test/run-make/codegen-options-parsing/Makefile +++ b/src/test/run-make/codegen-options-parsing/Makefile @@ -16,11 +16,11 @@ all: $(RUSTC) -C extra-filename=foo dummy.rs 2>&1 #Option taking no argument $(RUSTC) -C lto= dummy.rs 2>&1 | \ - $(CGREP) 'codegen option `lto` takes no value' + $(CGREP) 'codegen option `lto` - one of `thin`, `fat`, or' $(RUSTC) -C lto=1 dummy.rs 2>&1 | \ - $(CGREP) 'codegen option `lto` takes no value' + $(CGREP) 'codegen option `lto` - one of `thin`, `fat`, or' $(RUSTC) -C lto=foo dummy.rs 2>&1 | \ - $(CGREP) 'codegen option `lto` takes no value' + $(CGREP) 'codegen option `lto` - one of `thin`, `fat`, or' $(RUSTC) -C lto dummy.rs # Should not link dead code... diff --git a/src/test/run-pass/fat-lto.rs b/src/test/run-pass/fat-lto.rs new file mode 100644 index 00000000000..453eede261c --- /dev/null +++ b/src/test/run-pass/fat-lto.rs @@ -0,0 +1,17 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Clto=fat +// no-prefer-dynamic + +fn main() { + println!("hello!"); +} + diff --git a/src/test/run-pass/thinlto/all-crates.rs b/src/test/run-pass/thinlto/all-crates.rs new file mode 100644 index 00000000000..772a9ec8293 --- /dev/null +++ b/src/test/run-pass/thinlto/all-crates.rs @@ -0,0 +1,17 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Clto=thin +// no-prefer-dynamic +// min-llvm-version 4.0 + +fn main() { + println!("hello!"); +} diff --git a/src/test/run-pass/thinlto/thin-lto-inlines2.rs b/src/test/run-pass/thinlto/thin-lto-inlines2.rs index 0e8ad08a5f6..6020f72415d 100644 --- a/src/test/run-pass/thinlto/thin-lto-inlines2.rs +++ b/src/test/run-pass/thinlto/thin-lto-inlines2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -Z thinlto -C codegen-units=8 -O -C lto +// 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 -- cgit 1.4.1-3-g733a5 From 62afc43a84e64b18aff98067c0ea09adfc39b66d Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Wed, 24 Jan 2018 03:51:02 +0100 Subject: Make use of the implemented red/green algorithm for variance --- src/librustc_typeck/variance/constraints.rs | 45 +---------------------- src/librustc_typeck/variance/mod.rs | 4 -- src/test/compile-fail/dep-graph-variance-alias.rs | 2 +- 3 files changed, 2 insertions(+), 49 deletions(-) (limited to 'src/test') diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 0ed9b14b9d1..f7e10a4a47d 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -14,16 +14,12 @@ //! We walk the set of items and, for each member, generate new constraints. use hir::def_id::DefId; -use rustc::dep_graph::{DepGraphSafe, DepKind, DepNodeColor}; -use rustc::ich::StableHashingContext; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use syntax::ast; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; -use rustc_data_structures::stable_hasher::StableHashingContextProvider; - use super::terms::*; use super::terms::VarianceTerm::*; @@ -132,50 +128,11 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { } } -impl<'a, 'tcx> StableHashingContextProvider for ConstraintContext<'a, 'tcx> { - type ContextType = StableHashingContext<'tcx>; - - fn create_stable_hashing_context(&self) -> Self::ContextType { - self.terms_cx.tcx.create_stable_hashing_context() - } -} - -impl<'a, 'tcx> DepGraphSafe for ConstraintContext<'a, 'tcx> {} - impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { fn visit_node_helper(&mut self, id: ast::NodeId) { let tcx = self.terms_cx.tcx; let def_id = tcx.hir.local_def_id(id); - - // Encapsulate constructing the constraints into a task we can - // reference later. This can go away once the red-green - // algorithm is in place. - // - // See README.md for a detailed discussion - // on dep-graph management. - let dep_node = def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints); - - if let Some(DepNodeColor::Green(_)) = tcx.dep_graph.node_color(&dep_node) { - // If the corresponding node has already been marked as green, the - // appropriate portion of the DepGraph has already been loaded from - // the previous graph, so we don't do any dep-tracking. Since we - // don't cache any values though, we still have to re-run the - // computation. - tcx.dep_graph.with_ignore(|| { - self.build_constraints_for_item(def_id); - }); - } else { - tcx.dep_graph.with_task(dep_node, - self, - def_id, - visit_item_task); - } - - fn visit_item_task<'a, 'tcx>(ccx: &mut ConstraintContext<'a, 'tcx>, - def_id: DefId) - { - ccx.build_constraints_for_item(def_id); - } + self.build_constraints_for_item(def_id); } fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs index 418d2b94670..003ee6f2599 100644 --- a/src/librustc_typeck/variance/mod.rs +++ b/src/librustc_typeck/variance/mod.rs @@ -12,7 +12,6 @@ //! parameters. See README.md for details. use arena; -use rustc::dep_graph::DepKind; use rustc::hir; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::ty::{self, CrateVariancesMap, TyCtxt}; @@ -95,9 +94,6 @@ fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId) // Everything else must be inferred. let crate_map = tcx.crate_variances(LOCAL_CRATE); - let dep_node = item_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints); - tcx.dep_graph.read(dep_node); - crate_map.variances.get(&item_def_id) .unwrap_or(&crate_map.empty_variance) .clone() diff --git a/src/test/compile-fail/dep-graph-variance-alias.rs b/src/test/compile-fail/dep-graph-variance-alias.rs index 9b621a13fc4..18cfd001804 100644 --- a/src/test/compile-fail/dep-graph-variance-alias.rs +++ b/src/test/compile-fail/dep-graph-variance-alias.rs @@ -23,7 +23,7 @@ struct Foo { f: T } -#[rustc_if_this_changed] +#[rustc_if_this_changed(Krate)] type TypeAlias = Foo; #[rustc_then_this_would_need(ItemVariances)] //~ ERROR OK -- cgit 1.4.1-3-g733a5 From 5faba281ad08e6d57dc015f9547e18256eb8247f Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 24 Jan 2018 13:13:39 +0100 Subject: Fix ICE when use trees have multiple empty nested groups --- src/librustc_resolve/lib.rs | 10 +++++----- src/test/run-pass/issue-47673.rs | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 src/test/run-pass/issue-47673.rs (limited to 'src/test') diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 55c7e5f3924..42fc4143d90 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2045,7 +2045,7 @@ impl<'a> Resolver<'a> { segments: vec![], span: use_tree.span, }; - self.resolve_use_tree(item, use_tree, &path); + self.resolve_use_tree(item.id, use_tree, &path); } ItemKind::ExternCrate(_) | ItemKind::MacroDef(..) | ItemKind::GlobalAsm(_) => { @@ -2056,7 +2056,7 @@ impl<'a> Resolver<'a> { } } - fn resolve_use_tree(&mut self, item: &Item, use_tree: &ast::UseTree, prefix: &Path) { + fn resolve_use_tree(&mut self, id: NodeId, use_tree: &ast::UseTree, prefix: &Path) { match use_tree.kind { ast::UseTreeKind::Nested(ref items) => { let path = Path { @@ -2070,10 +2070,10 @@ impl<'a> Resolver<'a> { if items.len() == 0 { // Resolve prefix of an import with empty braces (issue #28388). - self.smart_resolve_path(item.id, None, &path, PathSource::ImportPrefix); + self.smart_resolve_path(id, None, &path, PathSource::ImportPrefix); } else { - for &(ref tree, _) in items { - self.resolve_use_tree(item, tree, &path); + for &(ref tree, nested_id) in items { + self.resolve_use_tree(nested_id, tree, &path); } } } diff --git a/src/test/run-pass/issue-47673.rs b/src/test/run-pass/issue-47673.rs new file mode 100644 index 00000000000..92f54a44f63 --- /dev/null +++ b/src/test/run-pass/issue-47673.rs @@ -0,0 +1,16 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(use_nested_groups)] +#![allow(unused_import)] + +use {{}, {}}; + +fn main() {} -- cgit 1.4.1-3-g733a5 From 5c5d9ddf6483b4897abfe55482bcee011b9452f8 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Wed, 24 Jan 2018 15:16:18 -0200 Subject: Add powerpc to run-pass/conditional-compile-arch.rs --- src/test/run-pass/conditional-compile-arch.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/test') diff --git a/src/test/run-pass/conditional-compile-arch.rs b/src/test/run-pass/conditional-compile-arch.rs index 3d8bf9333fd..1efbfb927fa 100644 --- a/src/test/run-pass/conditional-compile-arch.rs +++ b/src/test/run-pass/conditional-compile-arch.rs @@ -28,6 +28,9 @@ pub fn main() { } #[cfg(target_arch = "mips64")] pub fn main() { } +#[cfg(target_arch = "powerpc")] +pub fn main() { } + #[cfg(target_arch = "powerpc64")] pub fn main() { } -- cgit 1.4.1-3-g733a5 From 08ca4fd1358e172de351df475ea55b4e52605a21 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 25 Jan 2018 10:11:25 +0530 Subject: Add tests --- src/test/rustdoc/intra-links.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'src/test') diff --git a/src/test/rustdoc/intra-links.rs b/src/test/rustdoc/intra-links.rs index aa6f5538754..4726323e11c 100644 --- a/src/test/rustdoc/intra-links.rs +++ b/src/test/rustdoc/intra-links.rs @@ -10,7 +10,13 @@ // @has intra_links/index.html // @has - '//a/@href' '../intra_links/struct.ThisType.html' +// @has - '//a/@href' '../intra_links/struct.ThisType.html#method.this_method' // @has - '//a/@href' '../intra_links/enum.ThisEnum.html' +// @has - '//a/@href' '../intra_links/enum.ThisEnum.html#ThisVariant.v' +// @has - '//a/@href' '../intra_links/trait.ThisTrait.html' +// @has - '//a/@href' '../intra_links/trait.ThisTrait.html#tymethod.this_associated_method' +// @has - '//a/@href' '../intra_links/trait.ThisTrait.html#associatedtype.ThisAssociatedType' +// @has - '//a/@href' '../intra_links/trait.ThisTrait.html#associatedconstant.THIS_ASSOCIATED_CONST' // @has - '//a/@href' '../intra_links/trait.ThisTrait.html' // @has - '//a/@href' '../intra_links/type.ThisAlias.html' // @has - '//a/@href' '../intra_links/union.ThisUnion.html' @@ -23,8 +29,13 @@ //! In this crate we would like to link to: //! //! * [`ThisType`](ThisType) +//! * [`ThisType::this_method`](ThisType::this_method) //! * [`ThisEnum`](ThisEnum) +//! * [`ThisEnum::ThisVariant`](ThisEnum::ThisVariant) //! * [`ThisTrait`](ThisTrait) +//! * [`ThisTrait::this_associated_method`](ThisTrait::this_associated_method) +//! * [`ThisTrait::ThisAssociatedType`](ThisTrait::ThisAssociatedType) +//! * [`ThisTrait::THIS_ASSOCIATED_CONST`](ThisTrait::THIS_ASSOCIATED_CONST) //! * [`ThisAlias`](ThisAlias) //! * [`ThisUnion`](ThisUnion) //! * [`this_function`](this_function()) @@ -45,8 +56,16 @@ macro_rules! this_macro { } pub struct ThisType; + +impl ThisType { + pub fn this_method() {} +} pub enum ThisEnum { ThisVariant, } -pub trait ThisTrait {} +pub trait ThisTrait { + type ThisAssociatedType; + const THIS_ASSOCIATED_CONST: u8; + fn this_associated_method(); +} pub type ThisAlias = Result<(), ()>; pub union ThisUnion { this_field: usize, } -- cgit 1.4.1-3-g733a5 From 77bc826f90b479813f22bbae907c87a43693299b Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Thu, 25 Jan 2018 17:18:52 +0000 Subject: Fix rustdoc-js test --- src/test/rustdoc-js/from_u.js | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/test') diff --git a/src/test/rustdoc-js/from_u.js b/src/test/rustdoc-js/from_u.js index 0296788f7a0..34b98a758df 100644 --- a/src/test/rustdoc-js/from_u.js +++ b/src/test/rustdoc-js/from_u.js @@ -15,7 +15,5 @@ const EXPECTED = { { 'path': 'std::char', 'name': 'from_u32' }, { 'path': 'std::str', 'name': 'from_utf8' }, { 'path': 'std::string::String', 'name': 'from_utf8' }, - { 'path': 'std::i32', 'name': 'from_unsigned' }, - { 'path': 'std::i128', 'name': 'from_unsigned' }, ], }; -- cgit 1.4.1-3-g733a5 From 6006b67e6e051decb6f8a58aeee0ba1f085e8605 Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Thu, 25 Jan 2018 10:41:01 -0800 Subject: Fix regression: account for impl methods in arg count mismatch error --- src/librustc/traits/error_reporting.rs | 90 ++++++++++++++++++---------------- src/test/ui/issue-47706.rs | 24 +++++++++ src/test/ui/issue-47706.stderr | 13 +++++ 3 files changed, 86 insertions(+), 41 deletions(-) create mode 100644 src/test/ui/issue-47706.rs create mode 100644 src/test/ui/issue-47706.stderr (limited to 'src/test') diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 067340ecacc..42200a3a447 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -794,48 +794,56 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } fn get_fn_like_arguments(&self, node: hir::map::Node) -> (Span, Vec) { - if let hir::map::NodeExpr(&hir::Expr { - node: hir::ExprClosure(_, ref _decl, id, span, _), - .. - }) = node { - (self.tcx.sess.codemap().def_span(span), self.tcx.hir.body(id).arguments.iter() - .map(|arg| { - if let hir::Pat { - node: hir::PatKind::Tuple(args, _), - span, - .. - } = arg.pat.clone().into_inner() { - ArgKind::Tuple( + match node { + hir::map::NodeExpr(&hir::Expr { + node: hir::ExprClosure(_, ref _decl, id, span, _), + .. + }) => { + (self.tcx.sess.codemap().def_span(span), self.tcx.hir.body(id).arguments.iter() + .map(|arg| { + if let hir::Pat { + node: hir::PatKind::Tuple(args, _), span, - args.iter().map(|pat| { - let snippet = self.tcx.sess.codemap() - .span_to_snippet(pat.span).unwrap(); - (snippet, "_".to_owned()) - }).collect::>(), - ) - } else { - let name = self.tcx.sess.codemap().span_to_snippet(arg.pat.span).unwrap(); - ArgKind::Arg(name, "_".to_owned()) - } - }) - .collect::>()) - } else if let hir::map::NodeItem(&hir::Item { - span, - node: hir::ItemFn(ref decl, ..), - .. - }) = node { - (self.tcx.sess.codemap().def_span(span), decl.inputs.iter() - .map(|arg| match arg.clone().into_inner().node { - hir::TyTup(ref tys) => ArgKind::Tuple( - arg.span, - tys.iter() - .map(|_| ("_".to_owned(), "_".to_owned())) - .collect::>(), - ), - _ => ArgKind::Arg("_".to_owned(), "_".to_owned()) - }).collect::>()) - } else { - panic!("non-FnLike node found: {:?}", node); + .. + } = arg.pat.clone().into_inner() { + ArgKind::Tuple( + span, + args.iter().map(|pat| { + let snippet = self.tcx.sess.codemap() + .span_to_snippet(pat.span).unwrap(); + (snippet, "_".to_owned()) + }).collect::>(), + ) + } else { + let name = self.tcx.sess.codemap() + .span_to_snippet(arg.pat.span).unwrap(); + ArgKind::Arg(name, "_".to_owned()) + } + }) + .collect::>()) + } + hir::map::NodeItem(&hir::Item { + span, + node: hir::ItemFn(ref decl, ..), + .. + }) | + hir::map::NodeImplItem(&hir::ImplItem { + span, + node: hir::ImplItemKind::Method(hir::MethodSig { ref decl, .. }, _), + .. + }) => { + (self.tcx.sess.codemap().def_span(span), decl.inputs.iter() + .map(|arg| match arg.clone().into_inner().node { + hir::TyTup(ref tys) => ArgKind::Tuple( + arg.span, + tys.iter() + .map(|_| ("_".to_owned(), "_".to_owned())) + .collect::>(), + ), + _ => ArgKind::Arg("_".to_owned(), "_".to_owned()) + }).collect::>()) + } + _ => panic!("non-FnLike node found: {:?}", node), } } diff --git a/src/test/ui/issue-47706.rs b/src/test/ui/issue-47706.rs new file mode 100644 index 00000000000..24a0f66f5b1 --- /dev/null +++ b/src/test/ui/issue-47706.rs @@ -0,0 +1,24 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct Foo { + foo: Option, +} + +impl Foo { + pub fn new(foo: Option, _: ()) -> Foo { + Foo { foo } + } + + pub fn map(self) -> Option { + self.foo.map(Foo::new) + } + //~^^ ERROR function is expected to take 1 argument, but it takes 2 arguments [E0593] +} diff --git a/src/test/ui/issue-47706.stderr b/src/test/ui/issue-47706.stderr new file mode 100644 index 00000000000..0916dc64292 --- /dev/null +++ b/src/test/ui/issue-47706.stderr @@ -0,0 +1,13 @@ +error[E0601]: main function not found + +error[E0593]: function is expected to take 1 argument, but it takes 2 arguments + --> $DIR/issue-47706.rs:21:18 + | +16 | pub fn new(foo: Option, _: ()) -> Foo { + | ------------------------------------------ takes 2 arguments +... +21 | self.foo.map(Foo::new) + | ^^^ expected function that takes 1 argument + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 502de01ff40d37d3e6b419c3931a23284ce1a4e4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 25 Jan 2018 08:00:22 -0800 Subject: rustc: SIMD types use pointers in Rust's ABI This commit changes the ABI of SIMD types in the "Rust" ABI to unconditionally be passed via pointers instead of being passed as immediates. This should fix a longstanding issue, #44367, where SIMD-using programs ended up showing very odd behavior at runtime because the ABI between functions was mismatched. As a bit of a recap, this is sort of an LLVM bug and sort of an LLVM feature (today's behavior). LLVM will generate code for a function solely looking at the function it's generating, including calls to other functions. Let's then say you've got something that looks like: ```llvm define void @foo() { ; no target features enabled call void @bar( zeroinitializer) ret void } define void @bar() #0 { ; enables the AVX feature ... } ``` LLVM will codegen the call to `bar` *without* using AVX registers becauase `foo` doesn't have access to these registers. Instead it's generated with emulation that uses two 128-bit registers. The `bar` function, on the other hand, will expect its argument in an AVX register (as it has AVX enabled). This means we've got a codegen problem! Comments on #44367 have some more contexutal information but the crux of the issue is that if we want SIMD to work in general we'll need to ensure that whenever a function calls another they ABI of the arguments being passed is in agreement. One possible solution to this would be to insert "shim functions" where whenever a `target_feature` mismatch is detected the compiler inserts a shim function where you pass arguments via memory to the shim and then the shim loads the values and calls the target function (where the shim and the target have the same target features enabled). This unfortunately is quite nontrivial to implement in rustc today (especially when accounting for function pointers and such). This commit takes a different solution, *always* passing SIMD arguments through memory instead of passing as immediates. This strategy solves the problem at the LLVM layer because the ABI between two functions never uses SIMD registers. This also shouldn't be a hit to performance because SIMD performance is thought to often rely on inlining anyway, where a `call` instruction, even if using SIMD registers, would be disastrous to performance regardless. LLVM should then be more than capable of fixing all our memory usage to use registers instead after enough inlining has been performed. Note that there's a few caveats to this commit though: * The "platform intrinsic" ABI is omitted from "always pass via memory". This ABI is used to define intrinsics like `simd_shuffle4` where LLVM and rustc need to have the arguments as an immediate. * Additionally this commit does *not* fix the `extern` ("C") ABI. This means that the bug in #44367 can still happen when using non-Rust-ABI functions. My hope is that before stabilization we can ban and/or warn about SIMD types in these functions (as AFAIK there's not much motivation to belong there anyway), but I'll leave that for a later commit and if this is merged I'll file a follow-up issue. All in all this... Closes #44367 --- src/librustc_trans/abi.rs | 25 ++++ src/test/codegen/x86_mmx.rs | 4 +- src/test/run-pass/simd-target-feature-mixup.rs | 181 +++++++++++++++++++++++++ 3 files changed, 207 insertions(+), 3 deletions(-) create mode 100644 src/test/run-pass/simd-target-feature-mixup.rs (limited to 'src/test') diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 5079ce77523..9cabd9356e9 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -871,6 +871,31 @@ impl<'a, 'tcx> FnType<'tcx> { match arg.layout.abi { layout::Abi::Aggregate { .. } => {} + + // This is a fun case! The gist of what this is doing is + // that we want callers and callees to always agree on the + // ABI of how they pass SIMD arguments. If we were to *not* + // make these arguments indirect then they'd be immediates + // in LLVM, which means that they'd used whatever the + // appropriate ABI is for the callee and the caller. That + // means, for example, if the caller doesn't have AVX + // enabled but the callee does, then passing an AVX argument + // across this boundary would cause corrupt data to show up. + // + // This problem is fixed by unconditionally passing SIMD + // arguments through memory between callers and callees + // which should get them all to agree on ABI regardless of + // target feature sets. Some more information about this + // issue can be found in #44367. + // + // Note that the platform intrinsic ABI is exempt here as + // that's how we connect up to LLVM and it's unstable + // anyway, we control all calls to it in libstd. + layout::Abi::Vector { .. } if abi != Abi::PlatformIntrinsic => { + arg.make_indirect(); + return + } + _ => return } diff --git a/src/test/codegen/x86_mmx.rs b/src/test/codegen/x86_mmx.rs index bedda63bbff..dc9f63c35db 100644 --- a/src/test/codegen/x86_mmx.rs +++ b/src/test/codegen/x86_mmx.rs @@ -22,9 +22,7 @@ pub struct i8x8(u64); #[no_mangle] pub fn a(a: &mut i8x8, b: i8x8) -> i8x8 { - // CHECK-LABEL: define x86_mmx @a(x86_mmx*{{.*}}, x86_mmx{{.*}}) - // CHECK: store x86_mmx %b, x86_mmx* %a - // CHECK: ret x86_mmx %b + // CHECK-LABEL: define void @a(x86_mmx*{{.*}}, x86_mmx*{{.*}}, x86_mmx*{{.*}}) *a = b; return b } diff --git a/src/test/run-pass/simd-target-feature-mixup.rs b/src/test/run-pass/simd-target-feature-mixup.rs new file mode 100644 index 00000000000..b60aec2b5c9 --- /dev/null +++ b/src/test/run-pass/simd-target-feature-mixup.rs @@ -0,0 +1,181 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repr_simd, target_feature, cfg_target_feature)] + +use std::process::{Command, ExitStatus}; +use std::env; + +fn main() { + if let Some(level) = env::args().nth(1) { + return test::main(&level) + } + + let me = env::current_exe().unwrap(); + for level in ["sse", "avx", "avx512"].iter() { + let status = Command::new(&me).arg(level).status().unwrap(); + if status.success() { + println!("success with {}", level); + continue + } + + // We don't actually know if our computer has the requisite target features + // for the test below. Testing for that will get added to libstd later so + // for now just asume sigill means this is a machine that can't run this test. + if is_sigill(status) { + println!("sigill with {}, assuming spurious", level); + continue + } + panic!("invalid status at {}: {}", level, status); + } +} + +#[cfg(unix)] +fn is_sigill(status: ExitStatus) -> bool { + use std::os::unix::prelude::*; + status.signal() == Some(4) +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[allow(bad_style)] +mod test { + // An SSE type + #[repr(simd)] + #[derive(PartialEq, Debug, Clone, Copy)] + struct __m128i(u64, u64); + + // An AVX type + #[repr(simd)] + #[derive(PartialEq, Debug, Clone, Copy)] + struct __m256i(u64, u64, u64, u64); + + // An AVX-512 type + #[repr(simd)] + #[derive(PartialEq, Debug, Clone, Copy)] + struct __m512i(u64, u64, u64, u64, u64, u64, u64, u64); + + pub fn main(level: &str) { + unsafe { + main_normal(level); + main_sse(level); + if level == "sse" { + return + } + main_avx(level); + if level == "avx" { + return + } + main_avx512(level); + } + } + + macro_rules! mains { + ($( + $(#[$attr:meta])* + unsafe fn $main:ident(level: &str) { + ... + } + )*) => ($( + $(#[$attr])* + unsafe fn $main(level: &str) { + let m128 = __m128i(1, 2); + let m256 = __m256i(3, 4, 5, 6); + let m512 = __m512i(7, 8, 9, 10, 11, 12, 13, 14); + assert_eq!(id_sse_128(m128), m128); + assert_eq!(id_sse_256(m256), m256); + assert_eq!(id_sse_512(m512), m512); + + if level == "sse" { + return + } + assert_eq!(id_avx_128(m128), m128); + assert_eq!(id_avx_256(m256), m256); + assert_eq!(id_avx_512(m512), m512); + + if level == "avx" { + return + } + assert_eq!(id_avx512_128(m128), m128); + assert_eq!(id_avx512_256(m256), m256); + assert_eq!(id_avx512_512(m512), m512); + } + )*) + } + + mains! { + unsafe fn main_normal(level: &str) { ... } + #[target_feature(enable = "sse2")] + unsafe fn main_sse(level: &str) { ... } + #[target_feature(enable = "avx")] + unsafe fn main_avx(level: &str) { ... } + #[target_feature(enable = "avx512bw")] + unsafe fn main_avx512(level: &str) { ... } + } + + + #[target_feature(enable = "sse2")] + unsafe fn id_sse_128(a: __m128i) -> __m128i { + assert_eq!(a, __m128i(1, 2)); + a.clone() + } + + #[target_feature(enable = "sse2")] + unsafe fn id_sse_256(a: __m256i) -> __m256i { + assert_eq!(a, __m256i(3, 4, 5, 6)); + a.clone() + } + + #[target_feature(enable = "sse2")] + unsafe fn id_sse_512(a: __m512i) -> __m512i { + assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); + a.clone() + } + + #[target_feature(enable = "avx")] + unsafe fn id_avx_128(a: __m128i) -> __m128i { + assert_eq!(a, __m128i(1, 2)); + a.clone() + } + + #[target_feature(enable = "avx")] + unsafe fn id_avx_256(a: __m256i) -> __m256i { + assert_eq!(a, __m256i(3, 4, 5, 6)); + a.clone() + } + + #[target_feature(enable = "avx")] + unsafe fn id_avx_512(a: __m512i) -> __m512i { + assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); + a.clone() + } + + #[target_feature(enable = "avx512bw")] + unsafe fn id_avx512_128(a: __m128i) -> __m128i { + assert_eq!(a, __m128i(1, 2)); + a.clone() + } + + #[target_feature(enable = "avx512bw")] + unsafe fn id_avx512_256(a: __m256i) -> __m256i { + assert_eq!(a, __m256i(3, 4, 5, 6)); + a.clone() + } + + #[target_feature(enable = "avx512bw")] + unsafe fn id_avx512_512(a: __m512i) -> __m512i { + assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); + a.clone() + } +} + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +mod test { + pub fn main(level: &str) {} +} -- cgit 1.4.1-3-g733a5 From c199cb537065a8fabc6076a2090ea43205835f3c Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Thu, 25 Jan 2018 17:31:35 -0200 Subject: Make 3 run-pass tests works on android (aarch64 and x86) --- src/test/run-pass/intrinsic-alignment.rs | 15 ++------------- src/test/run-pass/rec-align-u64.rs | 12 ++---------- src/test/run-pass/signal-alternate-stack-cleanup.rs | 2 +- 3 files changed, 5 insertions(+), 24 deletions(-) (limited to 'src/test') diff --git a/src/test/run-pass/intrinsic-alignment.rs b/src/test/run-pass/intrinsic-alignment.rs index c7aa78e768f..5a6a6e0163e 100644 --- a/src/test/run-pass/intrinsic-alignment.rs +++ b/src/test/run-pass/intrinsic-alignment.rs @@ -19,7 +19,8 @@ mod rusti { } } -#[cfg(any(target_os = "cloudabi", +#[cfg(any(target_os = "android", + target_os = "cloudabi", target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", @@ -80,15 +81,3 @@ mod m { } } } - -#[cfg(target_os = "android")] -mod m { - #[main] - #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] - pub fn main() { - unsafe { - assert_eq!(::rusti::pref_align_of::(), 8); - assert_eq!(::rusti::min_align_of::(), 8); - } - } -} diff --git a/src/test/run-pass/rec-align-u64.rs b/src/test/run-pass/rec-align-u64.rs index 3ff8961166d..85c1b2adb79 100644 --- a/src/test/run-pass/rec-align-u64.rs +++ b/src/test/run-pass/rec-align-u64.rs @@ -38,7 +38,8 @@ struct Outer { } -#[cfg(any(target_os = "cloudabi", +#[cfg(any(target_os = "android", + target_os = "cloudabi", target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", @@ -85,15 +86,6 @@ mod m { } } -#[cfg(target_os = "android")] -mod m { - #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] - pub mod m { - pub fn align() -> usize { 8 } - pub fn size() -> usize { 16 } - } -} - pub fn main() { unsafe { let x = Outer {c8: 22, t: Inner {c64: 44}}; diff --git a/src/test/run-pass/signal-alternate-stack-cleanup.rs b/src/test/run-pass/signal-alternate-stack-cleanup.rs index 508fbe80ca4..eae431aa404 100644 --- a/src/test/run-pass/signal-alternate-stack-cleanup.rs +++ b/src/test/run-pass/signal-alternate-stack-cleanup.rs @@ -35,7 +35,7 @@ fn main() { unsafe { // Install signal hander that runs on alternate signal stack. let mut action: sigaction = std::mem::zeroed(); - action.sa_flags = SA_SIGINFO | SA_ONSTACK; + action.sa_flags = (SA_ONSTACK | SA_SIGINFO) as _; action.sa_sigaction = signal_handler as sighandler_t; sigaction(SIGWINCH, &action, std::ptr::null_mut()); -- cgit 1.4.1-3-g733a5 From 6e1cebb387fdae0d436d477697e3a2aae7c3772c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 25 Jan 2018 18:11:42 -0800 Subject: Shorten a filename for MSVC --- .../compile-fail/panic-runtime/auxiliary/depends.rs | 18 ++++++++++++++++++ .../auxiliary/runtime-depending-on-panic-runtime.rs | 18 ------------------ .../panic-runtime/runtime-depend-on-needs-runtime.rs | 4 ++-- 3 files changed, 20 insertions(+), 20 deletions(-) create mode 100644 src/test/compile-fail/panic-runtime/auxiliary/depends.rs delete mode 100644 src/test/compile-fail/panic-runtime/auxiliary/runtime-depending-on-panic-runtime.rs (limited to 'src/test') diff --git a/src/test/compile-fail/panic-runtime/auxiliary/depends.rs b/src/test/compile-fail/panic-runtime/auxiliary/depends.rs new file mode 100644 index 00000000000..b90dec9281b --- /dev/null +++ b/src/test/compile-fail/panic-runtime/auxiliary/depends.rs @@ -0,0 +1,18 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![feature(panic_runtime)] +#![crate_type = "rlib"] +#![panic_runtime] +#![no_std] + +extern crate needs_panic_runtime; diff --git a/src/test/compile-fail/panic-runtime/auxiliary/runtime-depending-on-panic-runtime.rs b/src/test/compile-fail/panic-runtime/auxiliary/runtime-depending-on-panic-runtime.rs deleted file mode 100644 index b90dec9281b..00000000000 --- a/src/test/compile-fail/panic-runtime/auxiliary/runtime-depending-on-panic-runtime.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2016 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// no-prefer-dynamic - -#![feature(panic_runtime)] -#![crate_type = "rlib"] -#![panic_runtime] -#![no_std] - -extern crate needs_panic_runtime; diff --git a/src/test/compile-fail/panic-runtime/runtime-depend-on-needs-runtime.rs b/src/test/compile-fail/panic-runtime/runtime-depend-on-needs-runtime.rs index 0681f991067..7cfdacbd983 100644 --- a/src/test/compile-fail/panic-runtime/runtime-depend-on-needs-runtime.rs +++ b/src/test/compile-fail/panic-runtime/runtime-depend-on-needs-runtime.rs @@ -9,7 +9,7 @@ // except according to those terms. // aux-build:needs-panic-runtime.rs -// aux-build:runtime-depending-on-panic-runtime.rs +// aux-build:depends.rs // error-pattern:cannot depend on a crate that needs a panic runtime -extern crate runtime_depending_on_panic_runtime; +extern crate depends; -- cgit 1.4.1-3-g733a5 From 68f2e1ebf2e0f959685fbce3f69349b3e21f34cc Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 25 Jan 2018 21:04:01 -0800 Subject: Ignore an i128 test on emscripten --- src/test/run-pass/issue-38763.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/test') diff --git a/src/test/run-pass/issue-38763.rs b/src/test/run-pass/issue-38763.rs index 4bf9513d64f..01cc8265a39 100644 --- a/src/test/run-pass/issue-38763.rs +++ b/src/test/run-pass/issue-38763.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-emscripten + #![feature(i128_type)] #[repr(C)] -- cgit 1.4.1-3-g733a5 From aca88e185a5233e6306bd6196864668b09342490 Mon Sep 17 00:00:00 2001 From: Björn Steinbrink Date: Fri, 26 Jan 2018 09:53:48 +0100 Subject: Upgrade LLVM to incorporate a fix for #47364 Fixes #47364 --- src/llvm | 2 +- src/rustllvm/llvm-rebuild-trigger | 2 +- src/test/run-pass/issue-47364.rs | 66 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/issue-47364.rs (limited to 'src/test') diff --git a/src/llvm b/src/llvm index 27174447533..bc344d5bc23 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 2717444753318e461e0c3b30dacd03ffbac96903 +Subproject commit bc344d5bc23c61ff9baf82d268a0edf199933cc3 diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger index 7f54d9276bf..2635ca73303 100644 --- a/src/rustllvm/llvm-rebuild-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2017-11-08 +2018-01-25 diff --git a/src/test/run-pass/issue-47364.rs b/src/test/run-pass/issue-47364.rs new file mode 100644 index 00000000000..2847ac2a0ba --- /dev/null +++ b/src/test/run-pass/issue-47364.rs @@ -0,0 +1,66 @@ +// Copyright 2017 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C codegen-units=8 -O + +fn main() { + nom_sql::selection(b"x "); +} + +pub enum Err

{ + Position(P), + NodePosition(u32), +} + +pub enum IResult { + Done(I,O), + Error(Err), + Incomplete(u32, u64) +} + +pub fn multispace(input: T) -> ::IResult { + ::IResult::Done(0, 0) +} + +mod nom_sql { + fn where_clause(i: &[u8]) -> ::IResult<&[u8], Option> { + let X = match ::multispace(i) { + ::IResult::Done(..) => ::IResult::Done(i, None::), + _ => ::IResult::Error(::Err::NodePosition(0)), + }; + match X { + ::IResult::Done(_, _) => ::IResult::Done(i, None), + _ => X + } + } + + pub fn selection(i: &[u8]) { + let Y = match { + match { + where_clause(i) + } { + ::IResult::Done(_, o) => ::IResult::Done(i, Some(o)), + ::IResult::Error(_) => ::IResult::Done(i, None), + _ => ::IResult::Incomplete(0, 0), + } + } { + ::IResult::Done(z, _) => ::IResult::Done(z, None::), + _ => return () + }; + match Y { + ::IResult::Done(x, _) => { + let bytes = b"; "; + let len = x.len(); + bytes[len]; + } + _ => () + } + } +} -- cgit 1.4.1-3-g733a5 From ac774e7a5bb7a404ddb26e2e9b9e6932cb31e1b6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 26 Jan 2018 06:48:38 -0800 Subject: Shorten another test path for MSVC --- .../trait_inheritance_cross_trait_call_xc_aux.rs | 22 ---------------------- src/test/run-pass/auxiliary/trait_xc_call_aux.rs | 22 ++++++++++++++++++++++ .../trait-inheritance-cross-trait-call-xc.rs | 4 ++-- 3 files changed, 24 insertions(+), 24 deletions(-) delete mode 100644 src/test/run-pass/auxiliary/trait_inheritance_cross_trait_call_xc_aux.rs create mode 100644 src/test/run-pass/auxiliary/trait_xc_call_aux.rs (limited to 'src/test') diff --git a/src/test/run-pass/auxiliary/trait_inheritance_cross_trait_call_xc_aux.rs b/src/test/run-pass/auxiliary/trait_inheritance_cross_trait_call_xc_aux.rs deleted file mode 100644 index 9eeb815c5de..00000000000 --- a/src/test/run-pass/auxiliary/trait_inheritance_cross_trait_call_xc_aux.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -pub trait Foo { - fn f(&self) -> isize; -} - -pub struct A { - pub x: isize -} - -impl Foo for A { - fn f(&self) -> isize { 10 } -} diff --git a/src/test/run-pass/auxiliary/trait_xc_call_aux.rs b/src/test/run-pass/auxiliary/trait_xc_call_aux.rs new file mode 100644 index 00000000000..9eeb815c5de --- /dev/null +++ b/src/test/run-pass/auxiliary/trait_xc_call_aux.rs @@ -0,0 +1,22 @@ +// Copyright 2012 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +pub trait Foo { + fn f(&self) -> isize; +} + +pub struct A { + pub x: isize +} + +impl Foo for A { + fn f(&self) -> isize { 10 } +} diff --git a/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs b/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs index e1610c1db07..3e68bea57c6 100644 --- a/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs +++ b/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// aux-build:trait_inheritance_cross_trait_call_xc_aux.rs +// aux-build:trait_xc_call_aux.rs -extern crate trait_inheritance_cross_trait_call_xc_aux as aux; +extern crate trait_xc_call_aux as aux; use aux::Foo; -- cgit 1.4.1-3-g733a5 From 9bb18239ded3369b64598fd0f9e3799e807dad9a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 26 Jan 2018 07:37:57 -0800 Subject: Fix a test case on Windows --- src/test/run-pass/simd-target-feature-mixup.rs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/test') diff --git a/src/test/run-pass/simd-target-feature-mixup.rs b/src/test/run-pass/simd-target-feature-mixup.rs index b60aec2b5c9..35ebc31b204 100644 --- a/src/test/run-pass/simd-target-feature-mixup.rs +++ b/src/test/run-pass/simd-target-feature-mixup.rs @@ -43,6 +43,11 @@ fn is_sigill(status: ExitStatus) -> bool { status.signal() == Some(4) } +#[cfg(windows)] +fn is_sigill(status: ExitStatus) -> bool { + status.code() == Some(0xc000001d) +} + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[allow(bad_style)] mod test { -- cgit 1.4.1-3-g733a5 From a06d333a148f6c620044a765f47497f1ed1e4dde Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 26 Jan 2018 09:41:00 -0800 Subject: Ignore a test on emscripten --- src/test/run-pass/simd-target-feature-mixup.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/test') diff --git a/src/test/run-pass/simd-target-feature-mixup.rs b/src/test/run-pass/simd-target-feature-mixup.rs index 35ebc31b204..2c9ef59709d 100644 --- a/src/test/run-pass/simd-target-feature-mixup.rs +++ b/src/test/run-pass/simd-target-feature-mixup.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-emscripten + #![feature(repr_simd, target_feature, cfg_target_feature)] use std::process::{Command, ExitStatus}; -- cgit 1.4.1-3-g733a5