Skip to content

Commit

Permalink
Auto merge of #57236 - pietroalbini:beta-backports, r=pietroalbini
Browse files Browse the repository at this point in the history
[beta] Rollup backports

* #56919: Remove a wrong multiplier on relocation offset computation
* #56916: Fix mutable references in `static mut`
* #56863: fix trait objects with a Self-containing projection values
* #56850: Fixed issue with using `Self` ctor in typedefs

r? @ghost
  • Loading branch information
bors committed Dec 31, 2018
2 parents a01b0bf + e6c5332 commit bab921d
Show file tree
Hide file tree
Showing 23 changed files with 454 additions and 66 deletions.
21 changes: 20 additions & 1 deletion src/librustc/traits/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,26 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
// In the case of a trait predicate, we can skip the "self" type.
data.skip_binder().input_types().skip(1).any(|t| t.has_self_ty())
}
ty::Predicate::Projection(..) |
ty::Predicate::Projection(ref data) => {
// And similarly for projections. This should be redundant with
// the previous check because any projection should have a
// matching `Trait` predicate with the same inputs, but we do
// the check to be safe.
//
// Note that we *do* allow projection *outputs* to contain
// `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`),
// we just require the user to specify *both* outputs
// in the object type (i.e., `dyn Foo<Output=(), Result=()>`).
//
// This is ALT2 in issue #56288, see that for discussion of the
// possible alternatives.
data.skip_binder()
.projection_ty
.trait_ref(self)
.input_types()
.skip(1)
.any(|t| t.has_self_ty())
}
ty::Predicate::WellFormed(..) |
ty::Predicate::ObjectSafe(..) |
ty::Predicate::TypeOutlives(..) |
Expand Down
84 changes: 52 additions & 32 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1754,17 +1754,19 @@ bitflags! {
pub struct AdtFlags: u32 {
const NO_ADT_FLAGS = 0;
const IS_ENUM = 1 << 0;
const IS_PHANTOM_DATA = 1 << 1;
const IS_FUNDAMENTAL = 1 << 2;
const IS_UNION = 1 << 3;
const IS_BOX = 1 << 4;
const IS_UNION = 1 << 1;
const IS_STRUCT = 1 << 2;
const HAS_CTOR = 1 << 3;
const IS_PHANTOM_DATA = 1 << 4;
const IS_FUNDAMENTAL = 1 << 5;
const IS_BOX = 1 << 6;
/// Indicates whether the type is an `Arc`.
const IS_ARC = 1 << 5;
const IS_ARC = 1 << 7;
/// Indicates whether the type is an `Rc`.
const IS_RC = 1 << 6;
const IS_RC = 1 << 8;
/// Indicates whether the variant list of this ADT is `#[non_exhaustive]`.
/// (i.e., this flag is never set unless this ADT is an enum).
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 7;
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 9;
}
}

Expand Down Expand Up @@ -2079,31 +2081,43 @@ impl<'a, 'gcx, 'tcx> AdtDef {
repr: ReprOptions) -> Self {
debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr);
let mut flags = AdtFlags::NO_ADT_FLAGS;

if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") {
debug!("found non-exhaustive variant list for {:?}", did);
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
}
flags |= match kind {
AdtKind::Enum => AdtFlags::IS_ENUM,
AdtKind::Union => AdtFlags::IS_UNION,
AdtKind::Struct => AdtFlags::IS_STRUCT,
};

if let AdtKind::Struct = kind {
let variant_def = &variants[VariantIdx::new(0)];
let def_key = tcx.def_key(variant_def.did);
match def_key.disambiguated_data.data {
DefPathData::StructCtor => flags |= AdtFlags::HAS_CTOR,
_ => (),
}
}

let attrs = tcx.get_attrs(did);
if attr::contains_name(&attrs, "fundamental") {
flags = flags | AdtFlags::IS_FUNDAMENTAL;
flags |= AdtFlags::IS_FUNDAMENTAL;
}
if Some(did) == tcx.lang_items().phantom_data() {
flags = flags | AdtFlags::IS_PHANTOM_DATA;
flags |= AdtFlags::IS_PHANTOM_DATA;
}
if Some(did) == tcx.lang_items().owned_box() {
flags = flags | AdtFlags::IS_BOX;
flags |= AdtFlags::IS_BOX;
}
if Some(did) == tcx.lang_items().arc() {
flags = flags | AdtFlags::IS_ARC;
flags |= AdtFlags::IS_ARC;
}
if Some(did) == tcx.lang_items().rc() {
flags = flags | AdtFlags::IS_RC;
}
if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") {
debug!("found non-exhaustive variant list for {:?}", did);
flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE;
}
match kind {
AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM,
AdtKind::Union => flags = flags | AdtFlags::IS_UNION,
AdtKind::Struct => {}
flags |= AdtFlags::IS_RC;
}

AdtDef {
did,
variants,
Expand All @@ -2114,25 +2128,25 @@ impl<'a, 'gcx, 'tcx> AdtDef {

#[inline]
pub fn is_struct(&self) -> bool {
!self.is_union() && !self.is_enum()
self.flags.contains(AdtFlags::IS_STRUCT)
}

#[inline]
pub fn is_union(&self) -> bool {
self.flags.intersects(AdtFlags::IS_UNION)
self.flags.contains(AdtFlags::IS_UNION)
}

#[inline]
pub fn is_enum(&self) -> bool {
self.flags.intersects(AdtFlags::IS_ENUM)
self.flags.contains(AdtFlags::IS_ENUM)
}

#[inline]
pub fn is_variant_list_non_exhaustive(&self) -> bool {
self.flags.intersects(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE)
self.flags.contains(AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE)
}

/// Returns the kind of the ADT - Struct or Enum.
/// Returns the kind of the ADT.
#[inline]
pub fn adt_kind(&self) -> AdtKind {
if self.is_enum() {
Expand Down Expand Up @@ -2161,33 +2175,39 @@ impl<'a, 'gcx, 'tcx> AdtDef {
}
}

/// Returns whether this type is #[fundamental] for the purposes
/// If this function returns `true`, it implies that `is_struct` must return `true`.
#[inline]
pub fn has_ctor(&self) -> bool {
self.flags.contains(AdtFlags::HAS_CTOR)
}

/// Returns whether this type is `#[fundamental]` for the purposes
/// of coherence checking.
#[inline]
pub fn is_fundamental(&self) -> bool {
self.flags.intersects(AdtFlags::IS_FUNDAMENTAL)
self.flags.contains(AdtFlags::IS_FUNDAMENTAL)
}

/// Returns `true` if this is PhantomData<T>.
#[inline]
pub fn is_phantom_data(&self) -> bool {
self.flags.intersects(AdtFlags::IS_PHANTOM_DATA)
self.flags.contains(AdtFlags::IS_PHANTOM_DATA)
}

/// Returns `true` if this is `Arc<T>`.
pub fn is_arc(&self) -> bool {
self.flags.intersects(AdtFlags::IS_ARC)
self.flags.contains(AdtFlags::IS_ARC)
}

/// Returns `true` if this is `Rc<T>`.
pub fn is_rc(&self) -> bool {
self.flags.intersects(AdtFlags::IS_RC)
self.flags.contains(AdtFlags::IS_RC)
}

/// Returns `true` if this is Box<T>.
#[inline]
pub fn is_box(&self) -> bool {
self.flags.intersects(AdtFlags::IS_BOX)
self.flags.contains(AdtFlags::IS_BOX)
}

/// Returns whether this type has a destructor.
Expand Down
9 changes: 7 additions & 2 deletions src/librustc_mir/interpret/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -708,8 +708,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
relocations
.iter()
.map(|&(offset, reloc)| {
(offset + dest.offset - src.offset + (i * size * relocations.len() as u64),
reloc)
// compute offset for current repetition
let dest_offset = dest.offset + (i * size);
(
// shift offsets from source allocation to destination allocation
offset + dest_offset - src.offset,
reloc,
)
})
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/transform/qualify_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {

// Only allow statics (not consts) to refer to other statics.
if self.mode == Mode::Static || self.mode == Mode::StaticMut {
if context.is_mutating_use() {
if self.mode == Mode::Static && context.is_mutating_use() {
// this is not strictly necessary as miri will also bail out
// For interior mutability we can't really catch this statically as that
// goes through raw pointers and intermediate temporaries, so miri has
Expand Down
28 changes: 26 additions & 2 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1013,15 +1013,39 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
let mut associated_types = BTreeSet::default();

for tr in traits::elaborate_trait_ref(tcx, principal) {
debug!("conv_object_ty_poly_trait_ref: observing object predicate `{:?}`", tr);
match tr {
ty::Predicate::Trait(pred) => {
associated_types.extend(tcx.associated_items(pred.def_id())
.filter(|item| item.kind == ty::AssociatedKind::Type)
.map(|item| item.def_id));
}
ty::Predicate::Projection(pred) => {
// Include projections defined on supertraits.
projection_bounds.push((pred, DUMMY_SP))
// A `Self` within the original bound will be substituted with a
// `TRAIT_OBJECT_DUMMY_SELF`, so check for that.
let references_self =
pred.skip_binder().ty.walk().any(|t| t == dummy_self);

// If the projection output contains `Self`, force the user to
// elaborate it explicitly to avoid a bunch of complexity.
//
// The "classicaly useful" case is the following:
// ```
// trait MyTrait: FnMut() -> <Self as MyTrait>::MyOutput {
// type MyOutput;
// }
// ```
//
// Here, the user could theoretically write `dyn MyTrait<Output=X>`,
// but actually supporting that would "expand" to an infinitely-long type
// `fix $ τ → dyn MyTrait<MyOutput=X, Output=<τ as MyTrait>::MyOutput`.
//
// Instead, we force the user to write `dyn MyTrait<MyOutput=X, Output=X>`,
// which is uglier but works. See the discussion in #56288 for alternatives.
if !references_self {
// Include projections defined on supertraits,
projection_bounds.push((pred, DUMMY_SP))
}
}
_ => ()
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/check/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
Def::Local(id) | Def::Upvar(id, ..) => {
Some(self.tcx.hir.span(id))
}
_ => self.tcx.hir.span_if_local(def.def_id())
_ => def.opt_def_id().and_then(|did| self.tcx.hir.span_if_local(did)),
};
if let Some(span) = def_span {
let label = match (unit_variant, inner_callee_path) {
Expand Down
67 changes: 45 additions & 22 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ use rustc::mir::interpret::{ConstValue, GlobalId};
use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs,
UserSelfTy, UserSubsts};
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind};
use rustc::ty::{self, AdtKind, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate,
RegionKind};
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::query::Providers;
Expand Down Expand Up @@ -3222,8 +3223,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
return_expr_ty);
}

// A generic function for checking the then and else in an if
// or if-else.
// A generic function for checking the 'then' and 'else' clauses in an 'if'
// or 'if-else' expression.
fn check_then_else(&self,
cond_expr: &'gcx hir::Expr,
then_expr: &'gcx hir::Expr,
Expand Down Expand Up @@ -3548,8 +3549,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {

// we don't look at stability attributes on
// struct-like enums (yet...), but it's definitely not
// a bug to have construct one.
if adt_kind != ty::AdtKind::Enum {
// a bug to have constructed one.
if adt_kind != AdtKind::Enum {
tcx.check_stability(v_field.did, Some(expr_id), field.span);
}

Expand Down Expand Up @@ -5161,26 +5162,48 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}).unwrap_or(false);

let mut new_def = def;
let (def_id, ty) = if let Def::SelfCtor(impl_def_id) = def {
let ty = self.impl_self_ty(span, impl_def_id).ty;

match ty.ty_adt_def() {
Some(adt_def) if adt_def.is_struct() => {
let variant = adt_def.non_enum_variant();
new_def = Def::StructCtor(variant.did, variant.ctor_kind);
(variant.did, self.tcx.type_of(variant.did))
}
_ => {
(impl_def_id, self.tcx.types.err)
let (def_id, ty) = match def {
Def::SelfCtor(impl_def_id) => {
let ty = self.impl_self_ty(span, impl_def_id).ty;
let adt_def = ty.ty_adt_def();

match adt_def {
Some(adt_def) if adt_def.has_ctor() => {
let variant = adt_def.non_enum_variant();
new_def = Def::StructCtor(variant.did, variant.ctor_kind);
(variant.did, self.tcx.type_of(variant.did))
}
_ => {
let mut err = self.tcx.sess.struct_span_err(span,
"the `Self` constructor can only be used with tuple or unit structs");
if let Some(adt_def) = adt_def {
match adt_def.adt_kind() {
AdtKind::Enum => {
err.note("did you mean to use one of the enum's variants?");
},
AdtKind::Struct |
AdtKind::Union => {
err.span_label(
span,
format!("did you mean `Self {{ /* fields */ }}`?"),
);
}
}
}
err.emit();

(impl_def_id, self.tcx.types.err)
}
}
}
} else {
let def_id = def.def_id();
_ => {
let def_id = def.def_id();

// The things we are substituting into the type should not contain
// escaping late-bound regions, and nor should the base type scheme.
let ty = self.tcx.type_of(def_id);
(def_id, ty)
// The things we are substituting into the type should not contain
// escaping late-bound regions, and nor should the base type scheme.
let ty = self.tcx.type_of(def_id);
(def_id, ty)
}
};

let substs = AstConv::create_substs_for_generic_args(
Expand Down
9 changes: 9 additions & 0 deletions src/test/ui/consts/promoted_regression.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// compile-pass

fn main() {
let _ = &[("", ""); 3];
}

const FOO: &[(&str, &str)] = &[("", ""); 3];
const BAR: &[(&str, &str); 5] = &[("", ""); 5];
const BAA: &[[&str; 12]; 11] = &[[""; 12]; 11];
7 changes: 7 additions & 0 deletions src/test/ui/consts/static_mut_containing_mut_ref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// compile-pass

static mut STDERR_BUFFER_SPACE: [u8; 42] = [0u8; 42];

pub static mut STDERR_BUFFER: *mut [u8] = unsafe { &mut STDERR_BUFFER_SPACE };

fn main() {}
9 changes: 9 additions & 0 deletions src/test/ui/consts/static_mut_containing_mut_ref2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#![feature(const_let)]

static mut STDERR_BUFFER_SPACE: u8 = 0;

pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; };
//~^ ERROR references in statics may only refer to immutable values
//~| ERROR static contains unimplemented expression type

fn main() {}
Loading

0 comments on commit bab921d

Please sign in to comment.