From 9f0168a9f3bc546f12d07018bdacbb1798c571e9 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Wed, 30 May 2018 00:25:56 +0900 Subject: [PATCH 01/10] Add notes on unsized argument errors. --- src/librustc/traits/error_reporting.rs | 3 +++ src/librustc/traits/mod.rs | 2 ++ src/librustc/traits/structural_impls.rs | 1 + src/librustc_typeck/check/mod.rs | 2 +- src/test/ui/issues/issue-38954.stderr | 1 + src/test/ui/issues/issue-41229-ref-str.stderr | 1 + src/test/ui/issues/issue-42312.stderr | 2 ++ 7 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 99b2f3e59feb6..bedee5dae5db8 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1455,6 +1455,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ObligationCauseCode::VariableType(_) => { err.note("all local variables must have a statically known size"); } + ObligationCauseCode::SizedArgumentType => { + err.note("all function arguments must have a statically known size"); + } ObligationCauseCode::SizedReturnType => { err.note("the return type of a function must have a \ statically known size"); diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 08434b5f24ef9..ef14d6d05c207 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -185,6 +185,8 @@ pub enum ObligationCauseCode<'tcx> { StructInitializerSized, /// Type of each variable must be Sized VariableType(ast::NodeId), + /// Argument type must be Sized + SizedArgumentType, /// Return type must be Sized SizedReturnType, /// Yield type must be Sized diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 544e3f03c03b1..9292b42eb525e 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -203,6 +203,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::StructInitializerSized => Some(super::StructInitializerSized), super::VariableType(id) => Some(super::VariableType(id)), super::ReturnType(id) => Some(super::ReturnType(id)), + super::SizedArgumentType => Some(super::SizedArgumentType), super::SizedReturnType => Some(super::SizedReturnType), super::SizedYieldType => Some(super::SizedYieldType), super::RepeatVec => Some(super::RepeatVec), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4fac11189a400..c7b717969ab8b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1049,7 +1049,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // for simple cases like `fn foo(x: Trait)`, // where we would error once on the parameter as a whole, and once on the binding `x`. if arg.pat.simple_ident().is_none() { - fcx.require_type_is_sized(arg_ty, decl.output.span(), traits::MiscObligation); + fcx.require_type_is_sized(arg_ty, decl.output.span(), traits::SizedArgumentType); } fcx.write_ty(arg.hir_id, arg_ty); diff --git a/src/test/ui/issues/issue-38954.stderr b/src/test/ui/issues/issue-38954.stderr index 2f0e579378ffc..9ecae90ff3a51 100644 --- a/src/test/ui/issues/issue-38954.stderr +++ b/src/test/ui/issues/issue-38954.stderr @@ -6,6 +6,7 @@ LL | fn _test(ref _p: str) {} | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit + = note: all function arguments must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/issues/issue-41229-ref-str.stderr b/src/test/ui/issues/issue-41229-ref-str.stderr index effc5f6999e36..75f43be77281f 100644 --- a/src/test/ui/issues/issue-41229-ref-str.stderr +++ b/src/test/ui/issues/issue-41229-ref-str.stderr @@ -6,6 +6,7 @@ LL | pub fn example(ref s: str) {} | = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit + = note: all function arguments must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/issues/issue-42312.stderr b/src/test/ui/issues/issue-42312.stderr index 8c2a0987f2f3f..0f383fe40a5d4 100644 --- a/src/test/ui/issues/issue-42312.stderr +++ b/src/test/ui/issues/issue-42312.stderr @@ -7,6 +7,7 @@ LL | fn baz(_: Self::Target) where Self: Deref {} = help: the trait `std::marker::Sized` is not implemented for `::Target` = note: to learn more, visit = help: consider adding a `where ::Target: std::marker::Sized` bound + = note: all function arguments must have a statically known size error[E0277]: the size for values of type `(dyn std::string::ToString + 'static)` cannot be known at compilation time --> $DIR/issue-42312.rs:18:23 @@ -16,6 +17,7 @@ LL | pub fn f(_: ToString) {} | = help: the trait `std::marker::Sized` is not implemented for `(dyn std::string::ToString + 'static)` = note: to learn more, visit + = note: all function arguments must have a statically known size error: aborting due to 2 previous errors From cd0476a390bbaf754501859bc56328b0078c88f5 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Tue, 29 May 2018 00:07:23 +0900 Subject: [PATCH 02/10] Add Builder::array_alloca. --- src/librustc_codegen_llvm/builder.rs | 19 +++++++++++++++++++ src/librustc_codegen_llvm/llvm/ffi.rs | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index b0f88bd4189d3..cfbc2ab90072d 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -445,6 +445,25 @@ impl Builder<'a, 'll, 'tcx> { } } + pub fn array_alloca(&self, + ty: &'ll Type, + len: &'ll Value, + name: &str, + align: Align) -> &'ll Value { + self.count_insn("alloca"); + unsafe { + let alloca = if name.is_empty() { + llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, noname()) + } else { + let name = SmallCStr::new(name); + llvm::LLVMBuildArrayAlloca(self.llbuilder, ty, len, + name.as_ptr()) + }; + llvm::LLVMSetAlignment(alloca, align.abi() as c_uint); + alloca + } + } + pub fn load(&self, ptr: &'ll Value, align: Align) -> &'ll Value { self.count_insn("load"); unsafe { diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index eec8a3a169ced..d3039a05b6db8 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -875,6 +875,11 @@ extern "C" { // Memory pub fn LLVMBuildAlloca(B: &Builder<'a>, Ty: &'a Type, Name: *const c_char) -> &'a Value; + pub fn LLVMBuildArrayAlloca(B: &Builder<'a>, + Ty: &'a Type, + Val: &'a Value, + Name: *const c_char) + -> &'a Value; pub fn LLVMBuildLoad(B: &Builder<'a>, PointerVal: &'a Value, Name: *const c_char) -> &'a Value; pub fn LLVMBuildStore(B: &Builder<'a>, Val: &'a Value, Ptr: &'a Value) -> &'a Value; From 7f05304068bf6a3b84b328ad6911f6645a0dbf40 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Tue, 29 May 2018 00:10:09 +0900 Subject: [PATCH 03/10] Add #![feature(unsized_locals)]. --- src/libsyntax/feature_gate.rs | 3 +++ src/test/ui/feature-gate-unsized_locals.rs | 15 +++++++++++++++ src/test/ui/feature-gate-unsized_locals.stderr | 13 +++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 src/test/ui/feature-gate-unsized_locals.rs create mode 100644 src/test/ui/feature-gate-unsized_locals.stderr diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 3b9e1b3c26566..e8245a553eb48 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -503,6 +503,9 @@ declare_features! ( // Allows `Self` in type definitions (active, self_in_typedefs, "1.30.0", Some(49303), None), + + // unsized rvalues at arguments and parameters + (active, unsized_locals, "1.30.0", Some(48055), None), ); declare_features! ( diff --git a/src/test/ui/feature-gate-unsized_locals.rs b/src/test/ui/feature-gate-unsized_locals.rs new file mode 100644 index 0000000000000..7f1f22fa38fb1 --- /dev/null +++ b/src/test/ui/feature-gate-unsized_locals.rs @@ -0,0 +1,15 @@ +// 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 f(f: FnOnce()) {} +//~^ ERROR E0277 + +fn main() { +} diff --git a/src/test/ui/feature-gate-unsized_locals.stderr b/src/test/ui/feature-gate-unsized_locals.stderr new file mode 100644 index 0000000000000..3cb0aa3b3eca5 --- /dev/null +++ b/src/test/ui/feature-gate-unsized_locals.stderr @@ -0,0 +1,13 @@ +error[E0277]: the size for values of type `(dyn std::ops::FnOnce() + 'static)` cannot be known at compilation time + --> $DIR/feature-gate-unsized_locals.rs:11:6 + | +LL | fn f(f: FnOnce()) {} + | ^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::FnOnce() + 'static)` + = note: to learn more, visit + = note: all local variables must have a statically known size + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From e2b95cb70e2142aab82a40115d11ff54a975335e Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Tue, 29 May 2018 00:11:34 +0900 Subject: [PATCH 04/10] Lift some Sized checks. --- src/librustc/traits/error_reporting.rs | 6 +++ .../borrow_check/nll/type_check/mod.rs | 45 ++++++++++++++----- src/librustc_typeck/check/mod.rs | 8 ++-- .../unsized-locals/unsized-exprs.rs | 36 +++++++++++++++ .../unsized-locals/unsized-exprs2.rs | 36 +++++++++++++++ .../associated-types-unsized.stderr | 1 + src/test/ui/error-codes/E0277.stderr | 1 + .../ui/feature-gate-unsized_locals.stderr | 1 + src/test/ui/issues/issue-15756.stderr | 1 + src/test/ui/issues/issue-27078.stderr | 1 + src/test/ui/issues/issue-38954.stderr | 1 + src/test/ui/issues/issue-41229-ref-str.stderr | 1 + src/test/ui/issues/issue-42312.stderr | 2 + src/test/ui/issues/issue-5883.stderr | 1 + src/test/ui/resolve/issue-5035-2.stderr | 1 + src/test/ui/str/str-array-assignment.stderr | 1 + .../trait-bounds-not-on-bare-trait.stderr | 1 + src/test/ui/unsized6.stderr | 10 +++++ 18 files changed, 140 insertions(+), 14 deletions(-) create mode 100644 src/test/compile-fail/unsized-locals/unsized-exprs.rs create mode 100644 src/test/compile-fail/unsized-locals/unsized-exprs2.rs diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index bedee5dae5db8..23736b1c77bb5 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1454,9 +1454,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } ObligationCauseCode::VariableType(_) => { err.note("all local variables must have a statically known size"); + if !self.tcx.features().unsized_locals { + err.help("unsized locals are gated as an unstable feature"); + } } ObligationCauseCode::SizedArgumentType => { err.note("all function arguments must have a statically known size"); + if !self.tcx.features().unsized_locals { + err.help("unsized locals are gated as an unstable feature"); + } } ObligationCauseCode::SizedReturnType => { err.note("the return type of a function must have a \ 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 9f790612124e6..ab83cfe25b590 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -903,11 +903,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ); } self.check_rvalue(mir, rv, location); - let trait_ref = ty::TraitRef { - def_id: tcx.lang_items().sized_trait().unwrap(), - substs: tcx.mk_substs_trait(place_ty, &[]), - }; - self.prove_trait_ref(trait_ref, location.interesting()); + if !self.tcx().features().unsized_locals { + let trait_ref = ty::TraitRef { + def_id: tcx.lang_items().sized_trait().unwrap(), + substs: tcx.mk_substs_trait(place_ty, &[]), + }; + self.prove_trait_ref(trait_ref, location.interesting()); + } } StatementKind::SetDiscriminant { ref place, @@ -962,6 +964,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { mir: &Mir<'tcx>, term: &Terminator<'tcx>, term_location: Location, + errors_buffer: &mut Option<&mut Vec>, ) { debug!("check_terminator: {:?}", term); let tcx = self.tcx(); @@ -1041,7 +1044,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { &sig, ); let sig = self.normalize(sig, term_location); - self.check_call_dest(mir, term, &sig, destination, term_location); + self.check_call_dest(mir, term, &sig, destination, term_location, errors_buffer); self.prove_predicates( sig.inputs().iter().map(|ty| ty::Predicate::WellFormed(ty)), @@ -1115,6 +1118,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { sig: &ty::FnSig<'tcx>, destination: &Option<(Place<'tcx>, BasicBlock)>, term_location: Location, + errors_buffer: &mut Option<&mut Vec>, ) { let tcx = self.tcx(); match *destination { @@ -1143,6 +1147,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { terr ); } + + // When `#![feature(unsized_locals)]` is not enabled, + // this check is done at `check_local`. + if self.tcx().features().unsized_locals { + let span = term.source_info.span; + self.ensure_place_sized(dest_ty, span, errors_buffer); + } } None => { // FIXME(canndrew): This is_never should probably be an is_uninhabited @@ -1309,14 +1320,26 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { LocalKind::Var | LocalKind::Temp => {} } - let span = local_decl.source_info.span; - let ty = local_decl.ty; + // When `#![feature(unsized_locals)]` is enabled, only function calls + // are checked in `check_call_dest`. + if !self.tcx().features().unsized_locals { + let span = local_decl.source_info.span; + let ty = local_decl.ty; + self.ensure_place_sized(ty, span, errors_buffer); + } + } + + fn ensure_place_sized(&mut self, + ty: Ty<'tcx>, + span: Span, + errors_buffer: &mut Option<&mut Vec>) { + let tcx = self.tcx(); // Erase the regions from `ty` to get a global type. The // `Sized` bound in no way depends on precise regions, so this // shouldn't affect `is_sized`. - let gcx = self.tcx().global_tcx(); - let erased_ty = gcx.lift(&self.tcx().erase_regions(&ty)).unwrap(); + let gcx = tcx.global_tcx(); + let erased_ty = gcx.lift(&tcx.erase_regions(&ty)).unwrap(); if !erased_ty.is_sized(gcx.at(span), self.param_env) { // in current MIR construction, all non-control-flow rvalue // expressions evaluate through `as_temp` or `into` a return @@ -1838,7 +1861,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { location.statement_index += 1; } - self.check_terminator(mir, block_data.terminator(), location); + self.check_terminator(mir, block_data.terminator(), location, &mut errors_buffer); self.check_iscleanup(mir, block_data); } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c7b717969ab8b..f73333df796b5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -961,8 +961,10 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { if let PatKind::Binding(_, _, ident, _) = p.node { let var_ty = self.assign(p.span, p.id, None); - self.fcx.require_type_is_sized(var_ty, p.span, - traits::VariableType(p.id)); + if !self.fcx.tcx.features().unsized_locals { + self.fcx.require_type_is_sized(var_ty, p.span, + traits::VariableType(p.id)); + } debug!("Pattern binding {} is assigned to {} with type {:?}", ident, @@ -1048,7 +1050,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // The check for a non-trivial pattern is a hack to avoid duplicate warnings // for simple cases like `fn foo(x: Trait)`, // where we would error once on the parameter as a whole, and once on the binding `x`. - if arg.pat.simple_ident().is_none() { + if arg.pat.simple_ident().is_none() && !fcx.tcx.features().unsized_locals { fcx.require_type_is_sized(arg_ty, decl.output.span(), traits::SizedArgumentType); } diff --git a/src/test/compile-fail/unsized-locals/unsized-exprs.rs b/src/test/compile-fail/unsized-locals/unsized-exprs.rs new file mode 100644 index 0000000000000..a09ccbb407e98 --- /dev/null +++ b/src/test/compile-fail/unsized-locals/unsized-exprs.rs @@ -0,0 +1,36 @@ +// 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(unsized_tuple_coercion, unsized_locals)] + +struct A(X); + +fn udrop(_x: T) {} +fn foo() -> Box<[u8]> { + Box::new(*b"foo") +} +fn tfoo() -> Box<(i32, [u8])> { + Box::new((42, *b"foo")) +} +fn afoo() -> Box> { + Box::new(A(*b"foo")) +} + +impl std::ops::Add for A<[u8]> { + type Output = (); + fn add(self, _rhs: i32) -> Self::Output {} +} + +fn main() { + udrop::<(i32, [u8])>((42, *foo())); + //~^ERROR E0277 + udrop::>(A { 0: *foo() }); + //~^ERROR E0277 +} diff --git a/src/test/compile-fail/unsized-locals/unsized-exprs2.rs b/src/test/compile-fail/unsized-locals/unsized-exprs2.rs new file mode 100644 index 0000000000000..40d6e54bd892f --- /dev/null +++ b/src/test/compile-fail/unsized-locals/unsized-exprs2.rs @@ -0,0 +1,36 @@ +// 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(unsized_tuple_coercion, unsized_locals)] + +struct A(X); + +fn udrop(_x: T) {} +fn foo() -> Box<[u8]> { + Box::new(*b"foo") +} +fn tfoo() -> Box<(i32, [u8])> { + Box::new((42, *b"foo")) +} +fn afoo() -> Box> { + Box::new(A(*b"foo")) +} + +impl std::ops::Add for A<[u8]> { + type Output = (); + fn add(self, _rhs: i32) -> Self::Output {} +} + +fn main() { + udrop::<[u8]>(foo()[..]); + //~^ERROR cannot move out of indexed content + // FIXME: should be error + udrop::>(A(*foo())); +} diff --git a/src/test/ui/associated-types/associated-types-unsized.stderr b/src/test/ui/associated-types/associated-types-unsized.stderr index 0b338c9ad45c5..09e3cb8c126a3 100644 --- a/src/test/ui/associated-types/associated-types-unsized.stderr +++ b/src/test/ui/associated-types/associated-types-unsized.stderr @@ -8,6 +8,7 @@ LL | let x = t.get(); //~ ERROR the size for values of type = note: to learn more, visit = help: consider adding a `where ::Value: std::marker::Sized` bound = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr index e4c2f10226799..ab9020222ea2b 100644 --- a/src/test/ui/error-codes/E0277.stderr +++ b/src/test/ui/error-codes/E0277.stderr @@ -8,6 +8,7 @@ LL | fn f(p: Path) { } = note: to learn more, visit = note: required because it appears within the type `std::path::Path` = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error[E0277]: the trait bound `i32: Foo` is not satisfied --> $DIR/E0277.rs:27:5 diff --git a/src/test/ui/feature-gate-unsized_locals.stderr b/src/test/ui/feature-gate-unsized_locals.stderr index 3cb0aa3b3eca5..a0440a373d2fc 100644 --- a/src/test/ui/feature-gate-unsized_locals.stderr +++ b/src/test/ui/feature-gate-unsized_locals.stderr @@ -7,6 +7,7 @@ LL | fn f(f: FnOnce()) {} = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::FnOnce() + 'static)` = note: to learn more, visit = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error: aborting due to previous error diff --git a/src/test/ui/issues/issue-15756.stderr b/src/test/ui/issues/issue-15756.stderr index e142a504eb638..877e0eaedf143 100644 --- a/src/test/ui/issues/issue-15756.stderr +++ b/src/test/ui/issues/issue-15756.stderr @@ -7,6 +7,7 @@ LL | &mut something = help: the trait `std::marker::Sized` is not implemented for `[T]` = note: to learn more, visit = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error: aborting due to previous error diff --git a/src/test/ui/issues/issue-27078.stderr b/src/test/ui/issues/issue-27078.stderr index 65b66997ee829..269a69dde3345 100644 --- a/src/test/ui/issues/issue-27078.stderr +++ b/src/test/ui/issues/issue-27078.stderr @@ -8,6 +8,7 @@ LL | fn foo(self) -> &'static i32 { = note: to learn more, visit = help: consider adding a `where Self: std::marker::Sized` bound = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error: aborting due to previous error diff --git a/src/test/ui/issues/issue-38954.stderr b/src/test/ui/issues/issue-38954.stderr index 9ecae90ff3a51..9bc937b97c9a1 100644 --- a/src/test/ui/issues/issue-38954.stderr +++ b/src/test/ui/issues/issue-38954.stderr @@ -7,6 +7,7 @@ LL | fn _test(ref _p: str) {} = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit = note: all function arguments must have a statically known size + = help: unsized locals are gated as an unstable feature error: aborting due to previous error diff --git a/src/test/ui/issues/issue-41229-ref-str.stderr b/src/test/ui/issues/issue-41229-ref-str.stderr index 75f43be77281f..e4a34fdaf48a4 100644 --- a/src/test/ui/issues/issue-41229-ref-str.stderr +++ b/src/test/ui/issues/issue-41229-ref-str.stderr @@ -7,6 +7,7 @@ LL | pub fn example(ref s: str) {} = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit = note: all function arguments must have a statically known size + = help: unsized locals are gated as an unstable feature error: aborting due to previous error diff --git a/src/test/ui/issues/issue-42312.stderr b/src/test/ui/issues/issue-42312.stderr index 0f383fe40a5d4..912d791b6bc3a 100644 --- a/src/test/ui/issues/issue-42312.stderr +++ b/src/test/ui/issues/issue-42312.stderr @@ -8,6 +8,7 @@ LL | fn baz(_: Self::Target) where Self: Deref {} = note: to learn more, visit = help: consider adding a `where ::Target: std::marker::Sized` bound = note: all function arguments must have a statically known size + = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `(dyn std::string::ToString + 'static)` cannot be known at compilation time --> $DIR/issue-42312.rs:18:23 @@ -18,6 +19,7 @@ LL | pub fn f(_: ToString) {} = help: the trait `std::marker::Sized` is not implemented for `(dyn std::string::ToString + 'static)` = note: to learn more, visit = note: all function arguments must have a statically known size + = help: unsized locals are gated as an unstable feature error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-5883.stderr b/src/test/ui/issues/issue-5883.stderr index 6a321abeaed9c..63dabd86ca89e 100644 --- a/src/test/ui/issues/issue-5883.stderr +++ b/src/test/ui/issues/issue-5883.stderr @@ -7,6 +7,7 @@ LL | fn new_struct(r: A+'static) = help: the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` = note: to learn more, visit = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time --> $DIR/issue-5883.rs:18:8 diff --git a/src/test/ui/resolve/issue-5035-2.stderr b/src/test/ui/resolve/issue-5035-2.stderr index 10d7a52297f55..9e7fca0508ef8 100644 --- a/src/test/ui/resolve/issue-5035-2.stderr +++ b/src/test/ui/resolve/issue-5035-2.stderr @@ -7,6 +7,7 @@ LL | fn foo(_x: K) {} = help: the trait `std::marker::Sized` is not implemented for `(dyn I + 'static)` = note: to learn more, visit = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error: aborting due to previous error diff --git a/src/test/ui/str/str-array-assignment.stderr b/src/test/ui/str/str-array-assignment.stderr index 59521bd2e2fab..57eff3fb13708 100644 --- a/src/test/ui/str/str-array-assignment.stderr +++ b/src/test/ui/str/str-array-assignment.stderr @@ -30,6 +30,7 @@ LL | let v = s[..2]; = help: the trait `std::marker::Sized` is not implemented for `str` = note: to learn more, visit = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error[E0308]: mismatched types --> $DIR/str-array-assignment.rs:19:17 diff --git a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr index b0c1c284f5ad0..ecabf9af27b38 100644 --- a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr +++ b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr @@ -7,6 +7,7 @@ LL | fn foo(_x: Foo + Send) { = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + std::marker::Send + 'static)` = note: to learn more, visit = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error: aborting due to previous error diff --git a/src/test/ui/unsized6.stderr b/src/test/ui/unsized6.stderr index 5dc12a344ad3f..5a09533269288 100644 --- a/src/test/ui/unsized6.stderr +++ b/src/test/ui/unsized6.stderr @@ -8,6 +8,7 @@ LL | let y: Y; = note: to learn more, visit = help: consider adding a `where Y: std::marker::Sized` bound = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:17:12 @@ -41,6 +42,7 @@ LL | let y: X; = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `Y` cannot be known at compilation time --> $DIR/unsized6.rs:27:12 @@ -63,6 +65,7 @@ LL | let y: X = *x1; = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:34:9 @@ -74,6 +77,7 @@ LL | let y = *x2; = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:36:10 @@ -85,6 +89,7 @@ LL | let (y, z) = (*x3, 4); = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:40:9 @@ -96,6 +101,7 @@ LL | let y: X = *x1; = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:42:9 @@ -107,6 +113,7 @@ LL | let y = *x2; = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:44:10 @@ -118,6 +125,7 @@ LL | let (y, z) = (*x3, 4); = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:48:18 @@ -129,6 +137,7 @@ LL | fn g1(x: X) {} = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error[E0277]: the size for values of type `X` cannot be known at compilation time --> $DIR/unsized6.rs:50:22 @@ -140,6 +149,7 @@ LL | fn g2(x: X) {} = note: to learn more, visit = help: consider adding a `where X: std::marker::Sized` bound = note: all local variables must have a statically known size + = help: unsized locals are gated as an unstable feature error: aborting due to 13 previous errors From 800f2c13a3f4213648f301dcd4e10d80b1e6ea38 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Tue, 29 May 2018 00:12:55 +0900 Subject: [PATCH 05/10] Implement simple codegen for unsized rvalues. --- src/librustc_codegen_llvm/abi.rs | 29 ++++++++- src/librustc_codegen_llvm/base.rs | 2 +- src/librustc_codegen_llvm/mir/block.rs | 27 +++++++- src/librustc_codegen_llvm/mir/mod.rs | 58 +++++++++++++---- src/librustc_codegen_llvm/mir/operand.rs | 46 ++++++++++++- src/librustc_codegen_llvm/mir/place.rs | 21 +++++- src/librustc_codegen_llvm/mir/rvalue.rs | 26 ++++++++ src/librustc_codegen_llvm/mir/statement.rs | 7 ++ src/librustc_target/abi/call/mod.rs | 28 ++++++++ src/librustc_target/abi/call/x86.rs | 1 + .../long-live-the-unsized-temporary.rs | 65 +++++++++++++++++++ .../reference-unsized-locals.rs | 17 +++++ .../unsized-locals/simple-unsized-locals.rs | 16 +++++ .../run-pass/unsized-locals/unsized-exprs.rs | 45 +++++++++++++ .../unsized-locals/unsized-parameters.rs | 20 ++++++ 15 files changed, 388 insertions(+), 20 deletions(-) create mode 100644 src/test/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs create mode 100644 src/test/run-pass/unsized-locals/reference-unsized-locals.rs create mode 100644 src/test/run-pass/unsized-locals/simple-unsized-locals.rs create mode 100644 src/test/run-pass/unsized-locals/unsized-exprs.rs create mode 100644 src/test/run-pass/unsized-locals/unsized-parameters.rs diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 44982eee86b3c..b8a67a60e62cb 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -189,6 +189,8 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> { let cx = bx.cx; if self.is_indirect() { OperandValue::Ref(val, self.layout.align).store(bx, dst) + } else if self.is_unsized_indirect() { + bug!("unsized ArgType must be handled through store_fn_arg"); } else if let PassMode::Cast(cast) = self.mode { // FIXME(eddyb): Figure out when the simpler Store is safe, clang // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. @@ -246,6 +248,9 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> { PassMode::Pair(..) => { OperandValue::Pair(next(), next()).store(bx, dst); } + PassMode::UnsizedIndirect(..) => { + OperandValue::UnsizedRef(next(), next()).store(bx, dst); + } PassMode::Direct(_) | PassMode::Indirect(_) | PassMode::Cast(_) => { self.store(bx, next(), dst); } @@ -302,6 +307,10 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { // Don't pass the vtable, it's not an argument of the virtual fn. // Instead, pass just the (thin pointer) first field of `*dyn Trait`. if arg_idx == Some(0) { + if layout.is_unsized() { + unimplemented!("by-value trait object is not \ + yet implemented in #![feature(unsized_locals)]"); + } // FIXME(eddyb) `layout.field(cx, 0)` is not enough because e.g. // `Box` has a few newtype wrappers around the raw // pointer, so we'd have to "dig down" to find `*dyn Trait`. @@ -538,7 +547,9 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { } let size = arg.layout.size; - if size > layout::Pointer.size(cx) { + if arg.layout.is_unsized() { + arg.make_unsized_indirect(None); + } else if size > layout::Pointer.size(cx) { arg.make_indirect(); } else { // We want to pass small aggregates as immediates, but using @@ -584,6 +595,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { llargument_tys.push(self.ret.memory_ty(cx).ptr_to()); Type::void(cx) } + PassMode::UnsizedIndirect(..) => bug!("return type must be sized"), }; for arg in &self.args { @@ -600,6 +612,13 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true)); continue; } + PassMode::UnsizedIndirect(..) => { + let ptr_ty = cx.tcx.mk_mut_ptr(arg.layout.ty); + let ptr_layout = cx.layout_of(ptr_ty); + llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 0, true)); + llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 1, true)); + continue; + } PassMode::Cast(cast) => cast.llvm_type(cx), PassMode::Indirect(_) => arg.memory_ty(cx).ptr_to(), }; @@ -651,6 +670,10 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { PassMode::Ignore => {} PassMode::Direct(ref attrs) | PassMode::Indirect(ref attrs) => apply(attrs), + PassMode::UnsizedIndirect(ref attrs, ref extra_attrs) => { + apply(attrs); + apply(extra_attrs); + } PassMode::Pair(ref a, ref b) => { apply(a); apply(b); @@ -695,6 +718,10 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { PassMode::Ignore => {} PassMode::Direct(ref attrs) | PassMode::Indirect(ref attrs) => apply(attrs), + PassMode::UnsizedIndirect(ref attrs, ref extra_attrs) => { + apply(attrs); + apply(extra_attrs); + } PassMode::Pair(ref a, ref b) => { apply(a); apply(b); diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index bd0c62e4766ae..49db35f586524 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -295,7 +295,7 @@ pub fn coerce_unsized_into( OperandValue::Immediate(base) => { unsize_thin_ptr(bx, base, src_ty, dst_ty) } - OperandValue::Ref(..) => bug!() + OperandValue::Ref(..) | OperandValue::UnsizedRef(..) => bug!() }; OperandValue::Pair(base, info).store(bx, dst); }; diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs index 4e389c3b915f0..52f8576d0d12a 100644 --- a/src/librustc_codegen_llvm/mir/block.rs +++ b/src/librustc_codegen_llvm/mir/block.rs @@ -32,7 +32,7 @@ use syntax_pos::Pos; use super::{FunctionCx, LocalRef}; use super::place::PlaceRef; use super::operand::OperandRef; -use super::operand::OperandValue::{Pair, Ref, Immediate}; +use super::operand::OperandValue::{Pair, Ref, UnsizedRef, Immediate}; impl FunctionCx<'a, 'll, 'tcx> { pub fn codegen_block(&mut self, bb: mir::BasicBlock) { @@ -234,6 +234,8 @@ impl FunctionCx<'a, 'll, 'tcx> { let op = self.codegen_consume(&bx, &mir::Place::Local(mir::RETURN_PLACE)); if let Ref(llval, align) = op.val { bx.load(llval, align) + } else if let UnsizedRef(..) = op.val { + bug!("return type must be sized"); } else { op.immediate_or_packed_pair(&bx) } @@ -249,6 +251,7 @@ impl FunctionCx<'a, 'll, 'tcx> { layout: cg_place.layout } } + LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), }; let llslot = match op.val { Immediate(_) | Pair(..) => { @@ -261,11 +264,14 @@ impl FunctionCx<'a, 'll, 'tcx> { "return place is unaligned!"); llval } + UnsizedRef(..) => bug!("return type must be sized"), }; bx.load( bx.pointercast(llslot, cast_ty.llvm_type(bx.cx).ptr_to()), self.fn_ty.ret.layout.align) } + + PassMode::UnsizedIndirect(..) => bug!("return value must be sized"), }; bx.ret(llval); } @@ -607,6 +613,10 @@ impl FunctionCx<'a, 'll, 'tcx> { op.val.store(&bx, tmp); op.val = Ref(tmp.llval, tmp.align); } + (&mir::Operand::Copy(_), UnsizedRef(..)) | + (&mir::Operand::Constant(_), UnsizedRef(..)) => { + bug!("tried to pass an unsized argument by copy or constant") + } _ => {} } @@ -657,6 +667,15 @@ impl FunctionCx<'a, 'll, 'tcx> { } _ => bug!("codegen_argument: {:?} invalid for pair arugment", op) } + } else if let PassMode::UnsizedIndirect(..) = arg.mode { + match op.val { + UnsizedRef(a, b) => { + llargs.push(a); + llargs.push(b); + return; + } + _ => bug!("codegen_argument: {:?} invalid for unsized indirect argument", op) + } } // Force by-ref if we have to load through a cast pointer. @@ -686,6 +705,8 @@ impl FunctionCx<'a, 'll, 'tcx> { (llval, align, true) } } + UnsizedRef(..) => + bug!("codegen_argument: tried to pass unsized operand to sized argument"), }; if by_ref && !arg.is_indirect() { @@ -727,6 +748,8 @@ impl FunctionCx<'a, 'll, 'tcx> { let field_ptr = tuple_ptr.project_field(bx, i); self.codegen_argument(bx, field_ptr.load(bx), llargs, &args[i]); } + } else if let UnsizedRef(..) = tuple.val { + bug!("closure arguments must be sized") } else { // If the tuple is immediate, the elements are as well. for i in 0..tuple.layout.fields.count() { @@ -820,6 +843,7 @@ impl FunctionCx<'a, 'll, 'tcx> { let dest = if let mir::Place::Local(index) = *dest { match self.locals[index] { LocalRef::Place(dest) => dest, + LocalRef::UnsizedPlace(_) => bug!("return type must be sized"), LocalRef::Operand(None) => { // Handle temporary places, specifically Operand ones, as // they don't have allocas @@ -871,6 +895,7 @@ impl FunctionCx<'a, 'll, 'tcx> { if let mir::Place::Local(index) = *dst { match self.locals[index] { LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place), + LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"), LocalRef::Operand(None) => { let dst_layout = bx.cx.layout_of(self.monomorphized_place_ty(dst)); assert!(!dst_layout.ty.has_erasable_regions()); diff --git a/src/librustc_codegen_llvm/mir/mod.rs b/src/librustc_codegen_llvm/mir/mod.rs index 8bb049be30549..d7bad05a66cef 100644 --- a/src/librustc_codegen_llvm/mir/mod.rs +++ b/src/librustc_codegen_llvm/mir/mod.rs @@ -180,6 +180,11 @@ impl FunctionCx<'a, 'll, 'tcx> { enum LocalRef<'ll, 'tcx> { Place(PlaceRef<'ll, 'tcx>), + /// `UnsizedPlace(p)`: `p` itself is a thin pointer (indirect place). + /// `*p` is the fat pointer that references the actual unsized place. + /// Every time it is initialized, we have to reallocate the place + /// and update the fat pointer. That's the reason why it is indirect. + UnsizedPlace(PlaceRef<'ll, 'tcx>), Operand(Option>), } @@ -275,17 +280,24 @@ pub fn codegen_mir( } debug!("alloc: {:?} ({}) -> place", local, name); - let place = PlaceRef::alloca(&bx, layout, &name.as_str()); - if dbg { - let (scope, span) = fx.debug_loc(mir::SourceInfo { - span: decl.source_info.span, - scope: decl.visibility_scope, - }); - declare_local(&bx, &fx.debug_context, name, layout.ty, scope.unwrap(), - VariableAccess::DirectVariable { alloca: place.llval }, - VariableKind::LocalVariable, span); + if layout.is_unsized() { + let indirect_place = + PlaceRef::alloca_unsized_indirect(&bx, layout, &name.as_str()); + // FIXME: add an appropriate debuginfo + LocalRef::UnsizedPlace(indirect_place) + } else { + let place = PlaceRef::alloca(&bx, layout, &name.as_str()); + if dbg { + let (scope, span) = fx.debug_loc(mir::SourceInfo { + span: decl.source_info.span, + scope: decl.visibility_scope, + }); + declare_local(&bx, &fx.debug_context, name, layout.ty, scope.unwrap(), + VariableAccess::DirectVariable { alloca: place.llval }, + VariableKind::LocalVariable, span); + } + LocalRef::Place(place) } - LocalRef::Place(place) } else { // Temporary or return place if local == mir::RETURN_PLACE && fx.fn_ty.ret.is_indirect() { @@ -294,7 +306,13 @@ pub fn codegen_mir( LocalRef::Place(PlaceRef::new_sized(llretptr, layout, layout.align)) } else if memory_locals.contains(local) { debug!("alloc: {:?} -> place", local); - LocalRef::Place(PlaceRef::alloca(&bx, layout, &format!("{:?}", local))) + if layout.is_unsized() { + let indirect_place = + PlaceRef::alloca_unsized_indirect(&bx, layout, &format!("{:?}", local)); + LocalRef::UnsizedPlace(indirect_place) + } else { + LocalRef::Place(PlaceRef::alloca(&bx, layout, &format!("{:?}", local))) + } } else { // If this is an immediate local, we do not create an // alloca in advance. Instead we wait until we see the @@ -531,6 +549,18 @@ fn arg_local_refs( bx.set_value_name(llarg, &name); llarg_idx += 1; PlaceRef::new_sized(llarg, arg.layout, arg.layout.align) + } else if arg.is_unsized_indirect() { + // As the storage for the indirect argument lives during + // the whole function call, we just copy the fat pointer. + let llarg = llvm::get_param(bx.llfn(), llarg_idx as c_uint); + llarg_idx += 1; + let llextra = llvm::get_param(bx.llfn(), llarg_idx as c_uint); + llarg_idx += 1; + let indirect_operand = OperandValue::Pair(llarg, llextra); + + let tmp = PlaceRef::alloca_unsized_indirect(bx, arg.layout, &name); + indirect_operand.store(&bx, tmp); + tmp } else { let tmp = PlaceRef::alloca(bx, arg.layout, &name); arg.store_fn_arg(bx, &mut llarg_idx, tmp); @@ -632,7 +662,11 @@ fn arg_local_refs( ); } }); - LocalRef::Place(place) + if arg.is_unsized_indirect() { + LocalRef::UnsizedPlace(place) + } else { + LocalRef::Place(place) + } }).collect() } diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs index f8166ee649147..ae929681b55ee 100644 --- a/src/librustc_codegen_llvm/mir/operand.rs +++ b/src/librustc_codegen_llvm/mir/operand.rs @@ -21,6 +21,8 @@ use common::{CodegenCx, C_undef, C_usize}; use builder::{Builder, MemFlags}; use value::Value; use type_of::LayoutLlvmExt; +use type_::Type; +use glue; use std::fmt; @@ -36,6 +38,10 @@ pub enum OperandValue<'ll> { /// A reference to the actual operand. The data is guaranteed /// to be valid for the operand's lifetime. Ref(&'ll Value, Align), + /// A reference to the unsized operand. The data is guaranteed + /// to be valid for the operand's lifetime. + /// The second field is the extra. + UnsizedRef(&'ll Value, &'ll Value), /// A single LLVM value. Immediate(&'ll Value), /// A pair of immediate LLVM values. Used by fat pointers too. @@ -148,7 +154,8 @@ impl OperandRef<'ll, 'tcx> { let (llptr, llextra) = match self.val { OperandValue::Immediate(llptr) => (llptr, None), OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)), - OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self) + OperandValue::Ref(..) | + OperandValue::UnsizedRef(..) => bug!("Deref of by-Ref operand {:?}", self) }; let layout = cx.layout_of(projected_ty); PlaceRef { @@ -243,7 +250,8 @@ impl OperandRef<'ll, 'tcx> { *a = bx.bitcast(*a, field.scalar_pair_element_llvm_type(bx.cx, 0, true)); *b = bx.bitcast(*b, field.scalar_pair_element_llvm_type(bx.cx, 1, true)); } - OperandValue::Ref(..) => bug!() + OperandValue::Ref(..) | + OperandValue::UnsizedRef(..) => bug!() } OperandRef { @@ -287,6 +295,9 @@ impl OperandValue<'ll> { base::memcpy_ty(bx, dest.llval, r, dest.layout, source_align.min(dest.align), flags) } + OperandValue::UnsizedRef(..) => { + bug!("cannot directly store unsized values"); + } OperandValue::Immediate(s) => { let val = base::from_immediate(bx, s); bx.store_with_flags(val, dest.llval, dest.align, flags); @@ -300,6 +311,35 @@ impl OperandValue<'ll> { } } } + + pub fn store_unsized(self, bx: &Builder<'a, 'll, 'tcx>, indirect_dest: PlaceRef<'ll, 'tcx>) { + debug!("OperandRef::store_unsized: operand={:?}, indirect_dest={:?}", self, indirect_dest); + let flags = MemFlags::empty(); + + // `indirect_dest` must have `*mut T` type. We extract `T` out of it. + let unsized_ty = indirect_dest.layout.ty.builtin_deref(true) + .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest)).ty; + + let (llptr, llextra) = + if let OperandValue::UnsizedRef(llptr, llextra) = self { + (llptr, llextra) + } else { + bug!("store_unsized called with a sized value") + }; + + // FIXME: choose an appropriate alignment, or use dynamic align somehow + let max_align = Align::from_bits(128, 128).unwrap(); + let min_align = Align::from_bits(8, 8).unwrap(); + + // Allocate an appropriate region on the stack, and copy the value into it + let (llsize, _) = glue::size_and_align_of_dst(&bx, unsized_ty, Some(llextra)); + let lldst = bx.array_alloca(Type::i8(bx.cx), llsize, "unsized_tmp", max_align); + base::call_memcpy(&bx, lldst, llptr, llsize, min_align, flags); + + // Store the allocated region and the extra to the indirect place. + let indirect_operand = OperandValue::Pair(lldst, llextra); + indirect_operand.store(&bx, indirect_dest); + } } impl FunctionCx<'a, 'll, 'tcx> { @@ -320,7 +360,7 @@ impl FunctionCx<'a, 'll, 'tcx> { LocalRef::Operand(None) => { bug!("use of {:?} before def", place); } - LocalRef::Place(..) => { + LocalRef::Place(..) | LocalRef::UnsizedPlace(..) => { // use path below } } diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs index 6fa0845dd0ceb..6e5d3dad25226 100644 --- a/src/librustc_codegen_llvm/mir/place.rs +++ b/src/librustc_codegen_llvm/mir/place.rs @@ -48,6 +48,7 @@ impl PlaceRef<'ll, 'tcx> { layout: TyLayout<'tcx>, align: Align, ) -> PlaceRef<'ll, 'tcx> { + assert!(!layout.is_unsized()); PlaceRef { llval, llextra: None, @@ -77,10 +78,21 @@ impl PlaceRef<'ll, 'tcx> { pub fn alloca(bx: &Builder<'a, 'll, 'tcx>, layout: TyLayout<'tcx>, name: &str) -> PlaceRef<'ll, 'tcx> { debug!("alloca({:?}: {:?})", name, layout); + assert!(!layout.is_unsized(), "tried to statically allocate unsized place"); let tmp = bx.alloca(layout.llvm_type(bx.cx), name, layout.align); Self::new_sized(tmp, layout, layout.align) } + /// Returns a place for an indirect reference to an unsized place. + pub fn alloca_unsized_indirect(bx: &Builder<'a, 'll, 'tcx>, layout: TyLayout<'tcx>, name: &str) + -> PlaceRef<'ll, 'tcx> { + debug!("alloca_unsized_indirect({:?}: {:?})", name, layout); + assert!(layout.is_unsized(), "tried to allocate indirect place for sized values"); + let ptr_ty = bx.cx.tcx.mk_mut_ptr(layout.ty); + let ptr_layout = bx.cx.layout_of(ptr_ty); + Self::alloca(bx, ptr_layout, name) + } + pub fn len(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Value { if let layout::FieldPlacement::Array { count, .. } = self.layout.fields { if self.layout.is_unsized() { @@ -97,7 +109,7 @@ impl PlaceRef<'ll, 'tcx> { pub fn load(&self, bx: &Builder<'a, 'll, 'tcx>) -> OperandRef<'ll, 'tcx> { debug!("PlaceRef::load: {:?}", self); - assert_eq!(self.llextra, None); + assert_eq!(self.llextra.is_some(), self.layout.is_unsized()); if self.layout.is_zst() { return OperandRef::new_zst(bx.cx, self.layout); @@ -119,7 +131,9 @@ impl PlaceRef<'ll, 'tcx> { } }; - let val = if self.layout.is_llvm_immediate() { + let val = if let Some(llextra) = self.llextra { + OperandValue::UnsizedRef(self.llval, llextra) + } else if self.layout.is_llvm_immediate() { let mut const_llval = None; unsafe { if let Some(global) = llvm::LLVMIsAGlobalVariable(self.llval) { @@ -424,6 +438,9 @@ impl FunctionCx<'a, 'll, 'tcx> { LocalRef::Place(place) => { return place; } + LocalRef::UnsizedPlace(place) => { + return place.load(bx).deref(&cx); + } LocalRef::Operand(..) => { bug!("using operand local {:?} as place", place); } diff --git a/src/librustc_codegen_llvm/mir/rvalue.rs b/src/librustc_codegen_llvm/mir/rvalue.rs index 7eac8e735edd4..ae318cda2022b 100644 --- a/src/librustc_codegen_llvm/mir/rvalue.rs +++ b/src/librustc_codegen_llvm/mir/rvalue.rs @@ -87,6 +87,9 @@ impl FunctionCx<'a, 'll, 'tcx> { let source = PlaceRef::new_sized(llref, operand.layout, align); base::coerce_unsized_into(&bx, source, dest); } + OperandValue::UnsizedRef(..) => { + bug!("unsized coercion on an unsized rvalue") + } } bx } @@ -175,6 +178,26 @@ impl FunctionCx<'a, 'll, 'tcx> { } } + pub fn codegen_rvalue_unsized(&mut self, + bx: Builder<'a, 'll, 'tcx>, + indirect_dest: PlaceRef<'ll, 'tcx>, + rvalue: &mir::Rvalue<'tcx>) + -> Builder<'a, 'll, 'tcx> + { + debug!("codegen_rvalue_unsized(indirect_dest.llval={:?}, rvalue={:?})", + indirect_dest.llval, rvalue); + + match *rvalue { + mir::Rvalue::Use(ref operand) => { + let cg_operand = self.codegen_operand(&bx, operand); + cg_operand.val.store_unsized(&bx, indirect_dest); + bx + } + + _ => bug!("unsized assignment other than Rvalue::Use"), + } + } + pub fn codegen_rvalue_operand(&mut self, bx: Builder<'a, 'll, 'tcx>, rvalue: &mir::Rvalue<'tcx>) @@ -245,6 +268,9 @@ impl FunctionCx<'a, 'll, 'tcx> { bug!("by-ref operand {:?} in codegen_rvalue_operand", operand); } + OperandValue::UnsizedRef(..) => { + bug!("unsized coercion on an unsized rvalue") + } } } mir::CastKind::Misc if operand.layout.is_llvm_scalar_pair() => { diff --git a/src/librustc_codegen_llvm/mir/statement.rs b/src/librustc_codegen_llvm/mir/statement.rs index 06340a3e5d8b4..dd62a12553caa 100644 --- a/src/librustc_codegen_llvm/mir/statement.rs +++ b/src/librustc_codegen_llvm/mir/statement.rs @@ -31,6 +31,9 @@ impl FunctionCx<'a, 'll, 'tcx> { LocalRef::Place(cg_dest) => { self.codegen_rvalue(bx, cg_dest, rvalue) } + LocalRef::UnsizedPlace(cg_indirect_dest) => { + self.codegen_rvalue_unsized(bx, cg_indirect_dest, rvalue) + } LocalRef::Operand(None) => { let (bx, operand) = self.codegen_rvalue_operand(bx, rvalue); self.locals[index] = LocalRef::Operand(Some(operand)); @@ -61,12 +64,16 @@ impl FunctionCx<'a, 'll, 'tcx> { mir::StatementKind::StorageLive(local) => { if let LocalRef::Place(cg_place) = self.locals[local] { cg_place.storage_live(&bx); + } else if let LocalRef::UnsizedPlace(cg_indirect_place) = self.locals[local] { + cg_indirect_place.storage_live(&bx); } bx } mir::StatementKind::StorageDead(local) => { if let LocalRef::Place(cg_place) = self.locals[local] { cg_place.storage_dead(&bx); + } else if let LocalRef::UnsizedPlace(cg_indirect_place) = self.locals[local] { + cg_indirect_place.storage_dead(&bx); } bx } diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index af874b1035b89..8647beef3d5c8 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -45,6 +45,8 @@ pub enum PassMode { Cast(CastTarget), /// Pass the argument indirectly via a hidden pointer. Indirect(ArgAttributes), + /// Pass the unsized argument indirectly via a hidden pointer. + UnsizedIndirect(ArgAttributes, ArgAttributes), } // Hack to disable non_upper_case_globals only for the bitflags! and not for the rest @@ -381,6 +383,25 @@ impl<'a, Ty> ArgType<'a, Ty> { } } + pub fn make_unsized_indirect(&mut self, vtable_size: Option) { + self.make_indirect(); + + let attrs = if let PassMode::Indirect(attrs) = self.mode { + attrs + } else { + unreachable!() + }; + + let mut extra_attrs = ArgAttributes::new(); + if let Some(vtable_size) = vtable_size { + extra_attrs.set(ArgAttribute::NoAlias) + .set(ArgAttribute::NonNull); + extra_attrs.pointee_size = vtable_size; + } + + self.mode = PassMode::UnsizedIndirect(attrs, extra_attrs); + } + pub fn extend_integer_width_to(&mut self, bits: u64) { // Only integers have signedness if let Abi::Scalar(ref scalar) = self.layout.abi { @@ -414,6 +435,13 @@ impl<'a, Ty> ArgType<'a, Ty> { } } + pub fn is_unsized_indirect(&self) -> bool { + match self.mode { + PassMode::UnsizedIndirect(..) => true, + _ => false + } + } + pub fn is_ignore(&self) -> bool { self.mode == PassMode::Ignore } diff --git a/src/librustc_target/abi/call/x86.rs b/src/librustc_target/abi/call/x86.rs index 0c0040de9df9f..6e64210a89001 100644 --- a/src/librustc_target/abi/call/x86.rs +++ b/src/librustc_target/abi/call/x86.rs @@ -102,6 +102,7 @@ pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>, flavor: Flav PassMode::Indirect(_) => continue, PassMode::Direct(ref mut attrs) => attrs, PassMode::Pair(..) | + PassMode::UnsizedIndirect(..) | PassMode::Cast(_) => { unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode) } diff --git a/src/test/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs b/src/test/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs new file mode 100644 index 0000000000000..e1fda427b4e73 --- /dev/null +++ b/src/test/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs @@ -0,0 +1,65 @@ +// 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(unsized_locals)] + +use std::fmt; + +fn gen_foo() -> Box { + Box::new(Box::new("foo")) +} + +fn foo(x: fmt::Display) { + assert_eq!(x.to_string(), "foo"); +} + +fn foo_indirect(x: fmt::Display) { + foo(x); +} + +fn main() { + foo(*gen_foo()); + foo_indirect(*gen_foo()); + + { + let x: fmt::Display = *gen_foo(); + foo(x); + } + + { + let x: fmt::Display = *gen_foo(); + let y: fmt::Display = *gen_foo(); + foo(x); + foo(y); + } + + { + let mut cnt: usize = 3; + let x = loop { + let x: fmt::Display = *gen_foo(); + if cnt == 0 { + break x; + } else { + cnt -= 1; + } + }; + foo(x); + } + + { + let x: fmt::Display = *gen_foo(); + let x = if true { + x + } else { + *gen_foo() + }; + foo(x); + } +} diff --git a/src/test/run-pass/unsized-locals/reference-unsized-locals.rs b/src/test/run-pass/unsized-locals/reference-unsized-locals.rs new file mode 100644 index 0000000000000..6ed39a78648a2 --- /dev/null +++ b/src/test/run-pass/unsized-locals/reference-unsized-locals.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. + +#![feature(unsized_locals)] + +fn main() { + let foo: Box<[u8]> = Box::new(*b"foo"); + let foo: [u8] = *foo; + assert_eq!(&foo, b"foo" as &[u8]); +} diff --git a/src/test/run-pass/unsized-locals/simple-unsized-locals.rs b/src/test/run-pass/unsized-locals/simple-unsized-locals.rs new file mode 100644 index 0000000000000..0b1aa6225eb50 --- /dev/null +++ b/src/test/run-pass/unsized-locals/simple-unsized-locals.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(unsized_locals)] + +fn main() { + let foo: Box<[u8]> = Box::new(*b"foo"); + let _foo: [u8] = *foo; +} diff --git a/src/test/run-pass/unsized-locals/unsized-exprs.rs b/src/test/run-pass/unsized-locals/unsized-exprs.rs new file mode 100644 index 0000000000000..9a5e534db25b3 --- /dev/null +++ b/src/test/run-pass/unsized-locals/unsized-exprs.rs @@ -0,0 +1,45 @@ +// 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(unsized_tuple_coercion, unsized_locals)] + +struct A(X); + +fn udrop(_x: T) {} +fn foo() -> Box<[u8]> { + Box::new(*b"foo") +} +fn tfoo() -> Box<(i32, [u8])> { + Box::new((42, *b"foo")) +} +fn afoo() -> Box> { + Box::new(A(*b"foo")) +} + +impl std::ops::Add for A<[u8]> { + type Output = (); + fn add(self, _rhs: i32) -> Self::Output {} +} + +fn main() { + udrop::<[u8]>(loop { + break *foo(); + }); + udrop::<[u8]>(if true { + *foo() + } else { + *foo() + }); + udrop::<[u8]>({*foo()}); + #[allow(unused_parens)] + udrop::<[u8]>((*foo())); + udrop::<[u8]>((*tfoo()).1); + *afoo() + 42; +} diff --git a/src/test/run-pass/unsized-locals/unsized-parameters.rs b/src/test/run-pass/unsized-locals/unsized-parameters.rs new file mode 100644 index 0000000000000..0314fe1d68662 --- /dev/null +++ b/src/test/run-pass/unsized-locals/unsized-parameters.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. + +#![feature(unsized_locals)] + +pub fn f0(_f: dyn FnOnce()) {} +pub fn f1(_s: str) {} +pub fn f2((_x, _y): (i32, [i32])) {} + +fn main() { + let foo = "foo".to_string().into_boxed_str(); + f1(*foo); +} From c72e87e30a46a1d0a97954d5fed965c88a0b7ce2 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Wed, 30 May 2018 00:33:01 +0900 Subject: [PATCH 06/10] Add an unstable-book article about unsized_locals. --- .../src/language-features/unsized-locals.md | 199 ++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 src/doc/unstable-book/src/language-features/unsized-locals.md diff --git a/src/doc/unstable-book/src/language-features/unsized-locals.md b/src/doc/unstable-book/src/language-features/unsized-locals.md new file mode 100644 index 0000000000000..ff5a6bcfbf736 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/unsized-locals.md @@ -0,0 +1,199 @@ +# `unsized_locals` + +The tracking issue for this feature is: [#48055] + +[#48055]: https://github.com/rust-lang/rust/issues/48055 + +------------------------ + +This implements [RFC1909]. When turned on, you can have unsized arguments and locals: + +[RFC1909]: https://github.com/rust-lang/rfcs/blob/master/text/1909-coercions.md + +```rust +#![feature(unsized_locals)] + +use std::any::Any; + +fn main() { + let x: Box = Box::new(42); + let x: dyn Any = *x; + // ^ unsized local variable + // ^^ unsized temporary + foo(x); +} + +fn foo(_: dyn Any) {} +// ^^^^^^ unsized argument +``` + +The RFC still forbids the following unsized expressions: + +```rust,ignore +#![feature(unsized_locals)] + +use std::any::Any; + +struct MyStruct { + content: T, +} + +struct MyTupleStruct(T); + +fn answer() -> Box { + Box::new(42) +} + +fn main() { + // You CANNOT have unsized statics. + static X: dyn Any = *answer(); // ERROR + const Y: dyn Any = *answer(); // ERROR + + // You CANNOT have struct initialized unsized. + MyStruct { content: *answer() }; // ERROR + MyTupleStruct(*answer()); // ERROR + (42, *answer()); // ERROR + + // You CANNOT have unsized return types. + fn my_function() -> dyn Any { *answer() } // ERROR + + // You CAN have unsized local variables... + let mut x: dyn Any = *answer(); // OK + // ...but you CANNOT reassign to them. + x = *answer(); // ERROR + + // You CANNOT even initialize them separately. + let y: dyn Any; // OK + y = *answer(); // ERROR + + // Not mentioned in the RFC, but by-move captured variables are also Sized. + let x: dyn Any = *answer(); + (move || { // ERROR + let y = x; + })(); + + // You CAN create a closure with unsized arguments, + // but you CANNOT call it. + // This is an implementation detail and may be changed in the future. + let f = |x: dyn Any| {}; + f(*answer()); // ERROR +} +``` + +However, the current implementation allows `MyTupleStruct(..)` to be unsized. This will be fixed in the future. + +## By-value trait objects + +With this feature, you can have by-value `self` arguments without `Self: Sized` bounds. + +```rust +#![feature(unsized_locals)] + +trait Foo { + fn foo(self) {} +} + +impl Foo for T {} + +fn main() { + let slice: Box<[i32]> = Box::new([1, 2, 3]); + <[i32] as Foo>::foo(*slice); +} +``` + +And `Foo` will also be object-safe. However, this object-safety is not yet implemented. + +```rust,ignore +#![feature(unsized_locals)] + +trait Foo { + fn foo(self) {} +} + +impl Foo for T {} + +fn main () { + let slice: Box = Box::new([1, 2, 3]); + // doesn't compile yet + ::foo(*slice); +} +``` + +Unfortunately, this is not implemented yet. + +One of the objectives of this feature is to allow `Box`, instead of `Box` in the future. See [#28796] for details. + +[#28796]: https://github.com/rust-lang/rust/issues/28796 + +## Variable length arrays + +The RFC also describes an extension to the array literal syntax `[e; n]`: you'll be able to specify non-const `n` to allocate variable length arrays on the stack. + +```rust,ignore +#![feature(unsized_locals)] + +fn mergesort(a: &mut [T]) { + let mut tmp = [T; a.len()]; + // ... +} + +fn main() { + let mut a = [3, 1, 5, 6]; + mergesort(&mut a); + assert_eq!(a, [1, 3, 5, 6]); +} +``` + +VLAs are not implemented yet. + +## Advisory on stack usage + +It's advised not to casually use the `#![feature(unsized_locals)]` feature. Typical use-cases are: + +- When you need a by-value trait objects. +- When you really need a fast allocation of small temporary arrays. + +Another pitfall is repetitive allocation and temporaries. Currently the compiler simply extends the stack frame every time it encounters an unsized assignment. So for example, the code + +```rust +#![feature(unsized_locals)] + +fn main() { + let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]); + let _x = {{{{{{{{{{*x}}}}}}}}}}; +} +``` + +and the code + +```rust +#![feature(unsized_locals)] + +fn main() { + for _ in 0..10 { + let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]); + let _x = *x; + } +} +``` + +will unnecessarily extend the stack frame. + +Allocation will be improved in the future, but there are still examples that are difficult to optimize: + +```rust +#![feature(unsized_locals)] + +fn main() { + let mut counter = 10; + let x = loop { + let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]); + let x = *x; + if counter > 0 { + counter -= 1; + } else { + break x; + } + }; +} +``` From 438edc3d5e60f82f22db07b6e8562fc8836a4cbe Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Thu, 12 Jul 2018 20:26:13 +0900 Subject: [PATCH 07/10] Update the unstable book regarding [e; dyn n]. --- .../unstable-book/src/language-features/unsized-locals.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/unsized-locals.md b/src/doc/unstable-book/src/language-features/unsized-locals.md index ff5a6bcfbf736..f779edc89e7d2 100644 --- a/src/doc/unstable-book/src/language-features/unsized-locals.md +++ b/src/doc/unstable-book/src/language-features/unsized-locals.md @@ -127,13 +127,13 @@ One of the objectives of this feature is to allow `Box`, instead of ## Variable length arrays -The RFC also describes an extension to the array literal syntax `[e; n]`: you'll be able to specify non-const `n` to allocate variable length arrays on the stack. +The RFC also describes an extension to the array literal syntax: `[e; dyn n]`. In the syntax, `n` isn't necessarily a constant expression. The array is dynamically allocated on the stack and has the type of `[T]`, instead of `[T; n]`. ```rust,ignore #![feature(unsized_locals)] fn mergesort(a: &mut [T]) { - let mut tmp = [T; a.len()]; + let mut tmp = [T; dyn a.len()]; // ... } @@ -144,7 +144,7 @@ fn main() { } ``` -VLAs are not implemented yet. +VLAs are not implemented yet. The syntax isn't final, either. We may need an alternative syntax for Rust 2015 because, in Rust 2015, expressions like `[e; dyn(1)]` would be ambiguous. One possible alternative proposed in the RFC is `[e; n]`: if `n` captures one or more local variables, then it is considered as `[e; dyn n]`. ## Advisory on stack usage From a0c422a752bdbe8f68b89f7656835bd7f36b2428 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Thu, 12 Jul 2018 20:27:10 +0900 Subject: [PATCH 08/10] Remove a now-unnecessary paragraph. The paragraph described a case where we can't optimize away repetitive dynamic stack allocation. However, as arielb1 pointed out, it can actually optimizable by dynamically delaying the stack unwinding. --- .../src/language-features/unsized-locals.md | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/unsized-locals.md b/src/doc/unstable-book/src/language-features/unsized-locals.md index f779edc89e7d2..7a5fe5b7f28cd 100644 --- a/src/doc/unstable-book/src/language-features/unsized-locals.md +++ b/src/doc/unstable-book/src/language-features/unsized-locals.md @@ -178,22 +178,3 @@ fn main() { ``` will unnecessarily extend the stack frame. - -Allocation will be improved in the future, but there are still examples that are difficult to optimize: - -```rust -#![feature(unsized_locals)] - -fn main() { - let mut counter = 10; - let x = loop { - let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]); - let x = *x; - if counter > 0 { - counter -= 1; - } else { - break x; - } - }; -} -``` From 6e15e7c1267e26d2bab3d0ded8454a2a45669d55 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Fri, 3 Aug 2018 23:32:21 +0900 Subject: [PATCH 09/10] Integrate PassMode::UnsizedIndirect into PassMode::Indirect. --- src/librustc_codegen_llvm/abi.rs | 33 ++++++++---------- src/librustc_codegen_llvm/mir/block.rs | 8 ++--- src/librustc_codegen_llvm/mir/mod.rs | 2 +- src/librustc_target/abi/call/mod.rs | 48 +++++++++++--------------- src/librustc_target/abi/call/x86.rs | 4 +-- 5 files changed, 42 insertions(+), 53 deletions(-) diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index b8a67a60e62cb..d699d786d1909 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -187,7 +187,7 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> { return; } let cx = bx.cx; - if self.is_indirect() { + if self.is_sized_indirect() { OperandValue::Ref(val, self.layout.align).store(bx, dst) } else if self.is_unsized_indirect() { bug!("unsized ArgType must be handled through store_fn_arg"); @@ -248,10 +248,10 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> { PassMode::Pair(..) => { OperandValue::Pair(next(), next()).store(bx, dst); } - PassMode::UnsizedIndirect(..) => { + PassMode::Indirect(_, Some(_)) => { OperandValue::UnsizedRef(next(), next()).store(bx, dst); } - PassMode::Direct(_) | PassMode::Indirect(_) | PassMode::Cast(_) => { + PassMode::Direct(_) | PassMode::Indirect(_, None) | PassMode::Cast(_) => { self.store(bx, next(), dst); } } @@ -547,9 +547,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { } let size = arg.layout.size; - if arg.layout.is_unsized() { - arg.make_unsized_indirect(None); - } else if size > layout::Pointer.size(cx) { + if arg.layout.is_unsized() || size > layout::Pointer.size(cx) { arg.make_indirect(); } else { // We want to pass small aggregates as immediates, but using @@ -565,7 +563,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { for arg in &mut self.args { fixup(arg); } - if let PassMode::Indirect(ref mut attrs) = self.ret.mode { + if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode { attrs.set(ArgAttribute::StructRet); } return; @@ -582,7 +580,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { if let PassMode::Pair(_, _) = arg.mode { 2 } else { 1 } ).sum(); let mut llargument_tys = Vec::with_capacity( - if let PassMode::Indirect(_) = self.ret.mode { 1 } else { 0 } + args_capacity + if let PassMode::Indirect(..) = self.ret.mode { 1 } else { 0 } + args_capacity ); let llreturn_ty = match self.ret.mode { @@ -591,11 +589,10 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { self.ret.layout.immediate_llvm_type(cx) } PassMode::Cast(cast) => cast.llvm_type(cx), - PassMode::Indirect(_) => { + PassMode::Indirect(..) => { llargument_tys.push(self.ret.memory_ty(cx).ptr_to()); Type::void(cx) } - PassMode::UnsizedIndirect(..) => bug!("return type must be sized"), }; for arg in &self.args { @@ -612,7 +609,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true)); continue; } - PassMode::UnsizedIndirect(..) => { + PassMode::Indirect(_, Some(_)) => { let ptr_ty = cx.tcx.mk_mut_ptr(arg.layout.ty); let ptr_layout = cx.layout_of(ptr_ty); llargument_tys.push(ptr_layout.scalar_pair_element_llvm_type(cx, 0, true)); @@ -620,7 +617,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { continue; } PassMode::Cast(cast) => cast.llvm_type(cx), - PassMode::Indirect(_) => arg.memory_ty(cx).ptr_to(), + PassMode::Indirect(_, None) => arg.memory_ty(cx).ptr_to(), }; llargument_tys.push(llarg_ty); } @@ -659,7 +656,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { PassMode::Direct(ref attrs) => { attrs.apply_llfn(llvm::AttributePlace::ReturnValue, llfn); } - PassMode::Indirect(ref attrs) => apply(attrs), + PassMode::Indirect(ref attrs, _) => apply(attrs), _ => {} } for arg in &self.args { @@ -669,8 +666,8 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { match arg.mode { PassMode::Ignore => {} PassMode::Direct(ref attrs) | - PassMode::Indirect(ref attrs) => apply(attrs), - PassMode::UnsizedIndirect(ref attrs, ref extra_attrs) => { + PassMode::Indirect(ref attrs, None) => apply(attrs), + PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => { apply(attrs); apply(extra_attrs); } @@ -693,7 +690,7 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { PassMode::Direct(ref attrs) => { attrs.apply_callsite(llvm::AttributePlace::ReturnValue, callsite); } - PassMode::Indirect(ref attrs) => apply(attrs), + PassMode::Indirect(ref attrs, _) => apply(attrs), _ => {} } if let layout::Abi::Scalar(ref scalar) = self.ret.layout.abi { @@ -717,8 +714,8 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { match arg.mode { PassMode::Ignore => {} PassMode::Direct(ref attrs) | - PassMode::Indirect(ref attrs) => apply(attrs), - PassMode::UnsizedIndirect(ref attrs, ref extra_attrs) => { + PassMode::Indirect(ref attrs, None) => apply(attrs), + PassMode::Indirect(ref attrs, Some(ref extra_attrs)) => { apply(attrs); apply(extra_attrs); } diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs index 52f8576d0d12a..1bd7bf48cda12 100644 --- a/src/librustc_codegen_llvm/mir/block.rs +++ b/src/librustc_codegen_llvm/mir/block.rs @@ -225,7 +225,7 @@ impl FunctionCx<'a, 'll, 'tcx> { mir::TerminatorKind::Return => { let llval = match self.fn_ty.ret.mode { - PassMode::Ignore | PassMode::Indirect(_) => { + PassMode::Ignore | PassMode::Indirect(..) => { bx.ret_void(); return; } @@ -270,8 +270,6 @@ impl FunctionCx<'a, 'll, 'tcx> { bx.pointercast(llslot, cast_ty.llvm_type(bx.cx).ptr_to()), self.fn_ty.ret.layout.align) } - - PassMode::UnsizedIndirect(..) => bug!("return value must be sized"), }; bx.ret(llval); } @@ -667,7 +665,7 @@ impl FunctionCx<'a, 'll, 'tcx> { } _ => bug!("codegen_argument: {:?} invalid for pair arugment", op) } - } else if let PassMode::UnsizedIndirect(..) = arg.mode { + } else if arg.is_unsized_indirect() { match op.val { UnsizedRef(a, b) => { llargs.push(a); @@ -682,7 +680,7 @@ impl FunctionCx<'a, 'll, 'tcx> { let (mut llval, align, by_ref) = match op.val { Immediate(_) | Pair(..) => { match arg.mode { - PassMode::Indirect(_) | PassMode::Cast(_) => { + PassMode::Indirect(..) | PassMode::Cast(_) => { let scratch = PlaceRef::alloca(bx, arg.layout, "arg"); op.val.store(bx, scratch); (scratch.llval, scratch.align, true) diff --git a/src/librustc_codegen_llvm/mir/mod.rs b/src/librustc_codegen_llvm/mir/mod.rs index d7bad05a66cef..5991bb80c30e6 100644 --- a/src/librustc_codegen_llvm/mir/mod.rs +++ b/src/librustc_codegen_llvm/mir/mod.rs @@ -541,7 +541,7 @@ fn arg_local_refs( } } - let place = if arg.is_indirect() { + let place = if arg.is_sized_indirect() { // Don't copy an indirect argument to an alloca, the caller // already put it in a temporary alloca and gave it up. // FIXME: lifetimes diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs index 8647beef3d5c8..78ed4b2d615a4 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/src/librustc_target/abi/call/mod.rs @@ -44,9 +44,9 @@ pub enum PassMode { /// a single uniform or a pair of registers. Cast(CastTarget), /// Pass the argument indirectly via a hidden pointer. - Indirect(ArgAttributes), - /// Pass the unsized argument indirectly via a hidden pointer. - UnsizedIndirect(ArgAttributes, ArgAttributes), + /// The second value, if any, is for the extra data (vtable or length) + /// which indicates that it refers to an unsized rvalue. + Indirect(ArgAttributes, Option), } // Hack to disable non_upper_case_globals only for the bitflags! and not for the rest @@ -370,38 +370,25 @@ impl<'a, Ty> ArgType<'a, Ty> { // i686-pc-windows-msvc, it results in wrong stack offsets. // attrs.pointee_align = Some(self.layout.align); - self.mode = PassMode::Indirect(attrs); + let extra_attrs = if self.layout.is_unsized() { + Some(ArgAttributes::new()) + } else { + None + }; + + self.mode = PassMode::Indirect(attrs, extra_attrs); } pub fn make_indirect_byval(&mut self) { self.make_indirect(); match self.mode { - PassMode::Indirect(ref mut attrs) => { + PassMode::Indirect(ref mut attrs, _) => { attrs.set(ArgAttribute::ByVal); } _ => unreachable!() } } - pub fn make_unsized_indirect(&mut self, vtable_size: Option) { - self.make_indirect(); - - let attrs = if let PassMode::Indirect(attrs) = self.mode { - attrs - } else { - unreachable!() - }; - - let mut extra_attrs = ArgAttributes::new(); - if let Some(vtable_size) = vtable_size { - extra_attrs.set(ArgAttribute::NoAlias) - .set(ArgAttribute::NonNull); - extra_attrs.pointee_size = vtable_size; - } - - self.mode = PassMode::UnsizedIndirect(attrs, extra_attrs); - } - pub fn extend_integer_width_to(&mut self, bits: u64) { // Only integers have signedness if let Abi::Scalar(ref scalar) = self.layout.abi { @@ -430,14 +417,21 @@ impl<'a, Ty> ArgType<'a, Ty> { pub fn is_indirect(&self) -> bool { match self.mode { - PassMode::Indirect(_) => true, + PassMode::Indirect(..) => true, + _ => false + } + } + + pub fn is_sized_indirect(&self) -> bool { + match self.mode { + PassMode::Indirect(_, None) => true, _ => false } } pub fn is_unsized_indirect(&self) -> bool { match self.mode { - PassMode::UnsizedIndirect(..) => true, + PassMode::Indirect(_, Some(_)) => true, _ => false } } @@ -534,7 +528,7 @@ impl<'a, Ty> FnType<'a, Ty> { a => return Err(format!("unrecognized arch \"{}\" in target specification", a)) } - if let PassMode::Indirect(ref mut attrs) = self.ret.mode { + if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode { attrs.set(ArgAttribute::StructRet); } diff --git a/src/librustc_target/abi/call/x86.rs b/src/librustc_target/abi/call/x86.rs index 6e64210a89001..1dcaafcf77fcf 100644 --- a/src/librustc_target/abi/call/x86.rs +++ b/src/librustc_target/abi/call/x86.rs @@ -99,10 +99,10 @@ pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>, flavor: Flav for arg in &mut fty.args { let attrs = match arg.mode { PassMode::Ignore | - PassMode::Indirect(_) => continue, + PassMode::Indirect(_, None) => continue, PassMode::Direct(ref mut attrs) => attrs, PassMode::Pair(..) | - PassMode::UnsizedIndirect(..) | + PassMode::Indirect(_, Some(_)) | PassMode::Cast(_) => { unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode) } From c488d59addf6bc66725a2ca7314629ee0f92b4e5 Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Fri, 3 Aug 2018 23:50:13 +0900 Subject: [PATCH 10/10] Integrate OperandValue::UnsizedRef into OperandValue::Ref. --- src/librustc_codegen_llvm/abi.rs | 4 +-- src/librustc_codegen_llvm/base.rs | 2 +- src/librustc_codegen_llvm/intrinsic.rs | 2 +- src/librustc_codegen_llvm/mir/block.rs | 31 +++++++++--------------- src/librustc_codegen_llvm/mir/operand.rs | 20 ++++++--------- src/librustc_codegen_llvm/mir/place.rs | 4 +-- src/librustc_codegen_llvm/mir/rvalue.rs | 7 ++---- 7 files changed, 27 insertions(+), 43 deletions(-) diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index d699d786d1909..79343505c78a5 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -188,7 +188,7 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> { } let cx = bx.cx; if self.is_sized_indirect() { - OperandValue::Ref(val, self.layout.align).store(bx, dst) + OperandValue::Ref(val, None, self.layout.align).store(bx, dst) } else if self.is_unsized_indirect() { bug!("unsized ArgType must be handled through store_fn_arg"); } else if let PassMode::Cast(cast) = self.mode { @@ -249,7 +249,7 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> { OperandValue::Pair(next(), next()).store(bx, dst); } PassMode::Indirect(_, Some(_)) => { - OperandValue::UnsizedRef(next(), next()).store(bx, dst); + OperandValue::Ref(next(), Some(next()), self.layout.align).store(bx, dst); } PassMode::Direct(_) | PassMode::Indirect(_, None) | PassMode::Cast(_) => { self.store(bx, next(), dst); diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 49db35f586524..bd0c62e4766ae 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -295,7 +295,7 @@ pub fn coerce_unsized_into( OperandValue::Immediate(base) => { unsize_thin_ptr(bx, base, src_ty, dst_ty) } - OperandValue::Ref(..) | OperandValue::UnsizedRef(..) => bug!() + OperandValue::Ref(..) => bug!() }; OperandValue::Pair(base, info).store(bx, dst); }; diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 099d8562aa536..be3e0d9d4b1ed 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -605,7 +605,7 @@ pub fn codegen_intrinsic_call( // etc. assert!(!bx.cx.type_needs_drop(arg.layout.ty)); let (ptr, align) = match arg.val { - OperandValue::Ref(ptr, align) => (ptr, align), + OperandValue::Ref(ptr, None, align) => (ptr, align), _ => bug!() }; let arg = PlaceRef::new_sized(ptr, arg.layout, align); diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs index 1bd7bf48cda12..5f718ae456c41 100644 --- a/src/librustc_codegen_llvm/mir/block.rs +++ b/src/librustc_codegen_llvm/mir/block.rs @@ -32,7 +32,7 @@ use syntax_pos::Pos; use super::{FunctionCx, LocalRef}; use super::place::PlaceRef; use super::operand::OperandRef; -use super::operand::OperandValue::{Pair, Ref, UnsizedRef, Immediate}; +use super::operand::OperandValue::{Pair, Ref, Immediate}; impl FunctionCx<'a, 'll, 'tcx> { pub fn codegen_block(&mut self, bb: mir::BasicBlock) { @@ -232,10 +232,8 @@ impl FunctionCx<'a, 'll, 'tcx> { PassMode::Direct(_) | PassMode::Pair(..) => { let op = self.codegen_consume(&bx, &mir::Place::Local(mir::RETURN_PLACE)); - if let Ref(llval, align) = op.val { + if let Ref(llval, _, align) = op.val { bx.load(llval, align) - } else if let UnsizedRef(..) = op.val { - bug!("return type must be sized"); } else { op.immediate_or_packed_pair(&bx) } @@ -247,7 +245,7 @@ impl FunctionCx<'a, 'll, 'tcx> { LocalRef::Operand(None) => bug!("use of return before def"), LocalRef::Place(cg_place) => { OperandRef { - val: Ref(cg_place.llval, cg_place.align), + val: Ref(cg_place.llval, None, cg_place.align), layout: cg_place.layout } } @@ -259,12 +257,11 @@ impl FunctionCx<'a, 'll, 'tcx> { op.val.store(&bx, scratch); scratch.llval } - Ref(llval, align) => { + Ref(llval, _, align) => { assert_eq!(align.abi(), op.layout.align.abi(), "return place is unaligned!"); llval } - UnsizedRef(..) => bug!("return type must be sized"), }; bx.load( bx.pointercast(llslot, cast_ty.llvm_type(bx.cx).ptr_to()), @@ -605,15 +602,11 @@ impl FunctionCx<'a, 'll, 'tcx> { // The callee needs to own the argument memory if we pass it // by-ref, so make a local copy of non-immediate constants. match (arg, op.val) { - (&mir::Operand::Copy(_), Ref(..)) | - (&mir::Operand::Constant(_), Ref(..)) => { + (&mir::Operand::Copy(_), Ref(_, None, _)) | + (&mir::Operand::Constant(_), Ref(_, None, _)) => { let tmp = PlaceRef::alloca(&bx, op.layout, "const"); op.val.store(&bx, tmp); - op.val = Ref(tmp.llval, tmp.align); - } - (&mir::Operand::Copy(_), UnsizedRef(..)) | - (&mir::Operand::Constant(_), UnsizedRef(..)) => { - bug!("tried to pass an unsized argument by copy or constant") + op.val = Ref(tmp.llval, None, tmp.align); } _ => {} } @@ -667,7 +660,7 @@ impl FunctionCx<'a, 'll, 'tcx> { } } else if arg.is_unsized_indirect() { match op.val { - UnsizedRef(a, b) => { + Ref(a, Some(b), _) => { llargs.push(a); llargs.push(b); return; @@ -690,7 +683,7 @@ impl FunctionCx<'a, 'll, 'tcx> { } } } - Ref(llval, align) => { + Ref(llval, _, align) => { if arg.is_indirect() && align.abi() < arg.layout.align.abi() { // `foo(packed.large_field)`. We can't pass the (unaligned) field directly. I // think that ATM (Rust 1.16) we only pass temporaries, but we shouldn't @@ -703,8 +696,6 @@ impl FunctionCx<'a, 'll, 'tcx> { (llval, align, true) } } - UnsizedRef(..) => - bug!("codegen_argument: tried to pass unsized operand to sized argument"), }; if by_ref && !arg.is_indirect() { @@ -740,13 +731,13 @@ impl FunctionCx<'a, 'll, 'tcx> { let tuple = self.codegen_operand(bx, operand); // Handle both by-ref and immediate tuples. - if let Ref(llval, align) = tuple.val { + if let Ref(llval, None, align) = tuple.val { let tuple_ptr = PlaceRef::new_sized(llval, tuple.layout, align); for i in 0..tuple.layout.fields.count() { let field_ptr = tuple_ptr.project_field(bx, i); self.codegen_argument(bx, field_ptr.load(bx), llargs, &args[i]); } - } else if let UnsizedRef(..) = tuple.val { + } else if let Ref(_, Some(_), _) = tuple.val { bug!("closure arguments must be sized") } else { // If the tuple is immediate, the elements are as well. diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs index ae929681b55ee..9537379813d52 100644 --- a/src/librustc_codegen_llvm/mir/operand.rs +++ b/src/librustc_codegen_llvm/mir/operand.rs @@ -37,11 +37,9 @@ use super::place::PlaceRef; pub enum OperandValue<'ll> { /// A reference to the actual operand. The data is guaranteed /// to be valid for the operand's lifetime. - Ref(&'ll Value, Align), - /// A reference to the unsized operand. The data is guaranteed - /// to be valid for the operand's lifetime. - /// The second field is the extra. - UnsizedRef(&'ll Value, &'ll Value), + /// The second value, if any, is the extra data (vtable or length) + /// which indicates that it refers to an unsized rvalue. + Ref(&'ll Value, Option<&'ll Value>, Align), /// A single LLVM value. Immediate(&'ll Value), /// A pair of immediate LLVM values. Used by fat pointers too. @@ -154,8 +152,7 @@ impl OperandRef<'ll, 'tcx> { let (llptr, llextra) = match self.val { OperandValue::Immediate(llptr) => (llptr, None), OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)), - OperandValue::Ref(..) | - OperandValue::UnsizedRef(..) => bug!("Deref of by-Ref operand {:?}", self) + OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self) }; let layout = cx.layout_of(projected_ty); PlaceRef { @@ -250,8 +247,7 @@ impl OperandRef<'ll, 'tcx> { *a = bx.bitcast(*a, field.scalar_pair_element_llvm_type(bx.cx, 0, true)); *b = bx.bitcast(*b, field.scalar_pair_element_llvm_type(bx.cx, 1, true)); } - OperandValue::Ref(..) | - OperandValue::UnsizedRef(..) => bug!() + OperandValue::Ref(..) => bug!() } OperandRef { @@ -291,11 +287,11 @@ impl OperandValue<'ll> { return; } match self { - OperandValue::Ref(r, source_align) => { + OperandValue::Ref(r, None, source_align) => { base::memcpy_ty(bx, dest.llval, r, dest.layout, source_align.min(dest.align), flags) } - OperandValue::UnsizedRef(..) => { + OperandValue::Ref(_, Some(_), _) => { bug!("cannot directly store unsized values"); } OperandValue::Immediate(s) => { @@ -321,7 +317,7 @@ impl OperandValue<'ll> { .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest)).ty; let (llptr, llextra) = - if let OperandValue::UnsizedRef(llptr, llextra) = self { + if let OperandValue::Ref(llptr, Some(llextra), _) = self { (llptr, llextra) } else { bug!("store_unsized called with a sized value") diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs index 6e5d3dad25226..89d41dcc8e994 100644 --- a/src/librustc_codegen_llvm/mir/place.rs +++ b/src/librustc_codegen_llvm/mir/place.rs @@ -132,7 +132,7 @@ impl PlaceRef<'ll, 'tcx> { }; let val = if let Some(llextra) = self.llextra { - OperandValue::UnsizedRef(self.llval, llextra) + OperandValue::Ref(self.llval, Some(llextra), self.align) } else if self.layout.is_llvm_immediate() { let mut const_llval = None; unsafe { @@ -163,7 +163,7 @@ impl PlaceRef<'ll, 'tcx> { }; OperandValue::Pair(load(0, a), load(1, b)) } else { - OperandValue::Ref(self.llval, self.align) + OperandValue::Ref(self.llval, None, self.align) }; OperandRef { val, layout: self.layout } diff --git a/src/librustc_codegen_llvm/mir/rvalue.rs b/src/librustc_codegen_llvm/mir/rvalue.rs index ae318cda2022b..84427d8b40f79 100644 --- a/src/librustc_codegen_llvm/mir/rvalue.rs +++ b/src/librustc_codegen_llvm/mir/rvalue.rs @@ -83,11 +83,11 @@ impl FunctionCx<'a, 'll, 'tcx> { base::coerce_unsized_into(&bx, scratch, dest); scratch.storage_dead(&bx); } - OperandValue::Ref(llref, align) => { + OperandValue::Ref(llref, None, align) => { let source = PlaceRef::new_sized(llref, operand.layout, align); base::coerce_unsized_into(&bx, source, dest); } - OperandValue::UnsizedRef(..) => { + OperandValue::Ref(_, Some(_), _) => { bug!("unsized coercion on an unsized rvalue") } } @@ -268,9 +268,6 @@ impl FunctionCx<'a, 'll, 'tcx> { bug!("by-ref operand {:?} in codegen_rvalue_operand", operand); } - OperandValue::UnsizedRef(..) => { - bug!("unsized coercion on an unsized rvalue") - } } } mir::CastKind::Misc if operand.layout.is_llvm_scalar_pair() => {