Skip to content

Commit c1c60d2

Browse files
committed
Auto merge of #61209 - matthewjasper:const-tuple-constructors, r=oli-obk
Make tuple constructors real const fns Mir construction special cases `Ctor(...)` to be lowered as `Ctor { 0: ... }`, which means this doesn't come up much in practice, but it seems inconsistent not to allow this. r? @oli-obk
2 parents ca1bcfd + bcf8365 commit c1c60d2

19 files changed

+516
-168
lines changed

src/librustc/ty/constness.rs

+19-13
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,38 @@ use crate::ty::query::Providers;
22
use crate::hir::def_id::DefId;
33
use crate::hir;
44
use crate::ty::TyCtxt;
5-
use syntax_pos::symbol::Symbol;
5+
use syntax_pos::symbol::{sym, Symbol};
66
use crate::hir::map::blocks::FnLikeNode;
77
use syntax::attr;
88

99
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
1010
/// Whether the `def_id` counts as const fn in your current crate, considering all active
1111
/// feature gates
1212
pub fn is_const_fn(self, def_id: DefId) -> bool {
13-
self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) {
14-
Some(stab) => match stab.const_stability {
13+
self.is_const_fn_raw(def_id) && match self.is_unstable_const_fn(def_id) {
14+
Some(feature_name) => {
1515
// has a `rustc_const_unstable` attribute, check whether the user enabled the
16-
// corresponding feature gate
17-
Some(feature_name) => self.features()
16+
// corresponding feature gate, const_constructor is not a lib feature, so has
17+
// to be checked separately.
18+
self.features()
1819
.declared_lib_features
1920
.iter()
20-
.any(|&(sym, _)| sym == feature_name),
21-
// the function has no stability attribute, it is stable as const fn or the user
22-
// needs to use feature gates to use the function at all
23-
None => true,
21+
.any(|&(sym, _)| sym == feature_name)
22+
|| (feature_name == sym::const_constructor
23+
&& self.features().const_constructor)
2424
},
25-
// functions without stability are either stable user written const fn or the user is
26-
// using feature gates and we thus don't care what they do
25+
// functions without const stability are either stable user written
26+
// const fn or the user is using feature gates and we thus don't
27+
// care what they do
2728
None => true,
2829
}
2930
}
3031

3132
/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
3233
pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
33-
if self.is_const_fn_raw(def_id) {
34+
if self.is_constructor(def_id) {
35+
Some(sym::const_constructor)
36+
} else if self.is_const_fn_raw(def_id) {
3437
self.lookup_stability(def_id)?.const_stability
3538
} else {
3639
None
@@ -70,8 +73,11 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
7073
let hir_id = tcx.hir().as_local_hir_id(def_id)
7174
.expect("Non-local call to local provider is_const_fn");
7275

73-
if let Some(fn_like) = FnLikeNode::from_node(tcx.hir().get_by_hir_id(hir_id)) {
76+
let node = tcx.hir().get_by_hir_id(hir_id);
77+
if let Some(fn_like) = FnLikeNode::from_node(node) {
7478
fn_like.constness() == hir::Constness::Const
79+
} else if let hir::Node::Ctor(_) = node {
80+
true
7581
} else {
7682
false
7783
}

src/librustc_metadata/decoder.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,7 @@ impl<'a, 'tcx> CrateMetadata {
11671167
let constness = match self.entry(id).kind {
11681168
EntryKind::Method(data) => data.decode(self).fn_data.constness,
11691169
EntryKind::Fn(data) => data.decode(self).constness,
1170+
EntryKind::Variant(..) | EntryKind::Struct(..) => hir::Constness::Const,
11701171
_ => hir::Constness::NotConst,
11711172
};
11721173
constness == hir::Constness::Const

src/librustc_mir/borrow_check/mod.rs

-28
Original file line numberDiff line numberDiff line change
@@ -91,34 +91,6 @@ fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> BorrowC
9191
let input_mir = tcx.mir_validated(def_id);
9292
debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id));
9393

94-
// We are not borrow checking the automatically generated struct/variant constructors
95-
// because we want to accept structs such as this (taken from the `linked-hash-map`
96-
// crate):
97-
// ```rust
98-
// struct Qey<Q: ?Sized>(Q);
99-
// ```
100-
// MIR of this struct constructor looks something like this:
101-
// ```rust
102-
// fn Qey(_1: Q) -> Qey<Q>{
103-
// let mut _0: Qey<Q>; // return place
104-
//
105-
// bb0: {
106-
// (_0.0: Q) = move _1; // bb0[0]: scope 0 at src/main.rs:1:1: 1:26
107-
// return; // bb0[1]: scope 0 at src/main.rs:1:1: 1:26
108-
// }
109-
// }
110-
// ```
111-
// The problem here is that `(_0.0: Q) = move _1;` is valid only if `Q` is
112-
// of statically known size, which is not known to be true because of the
113-
// `Q: ?Sized` constraint. However, it is true because the constructor can be
114-
// called only when `Q` is of statically known size.
115-
if tcx.is_constructor(def_id) {
116-
return BorrowCheckResult {
117-
closure_requirements: None,
118-
used_mut_upvars: SmallVec::new(),
119-
};
120-
}
121-
12294
let opt_closure_req = tcx.infer_ctxt().enter(|infcx| {
12395
let input_mir: &Body<'_> = &input_mir.borrow();
12496
do_mir_borrowck(&infcx, input_mir, def_id)

src/librustc_mir/build/mod.rs

-35
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use crate::build;
22
use crate::build::scope::DropKind;
33
use crate::hair::cx::Cx;
44
use crate::hair::{LintLevel, BindingMode, PatternKind};
5-
use crate::shim;
65
use crate::transform::MirSource;
76
use crate::util as mir_util;
87
use rustc::hir;
@@ -31,8 +30,6 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Body<'
3130

3231
// Figure out what primary body this item has.
3332
let (body_id, return_ty_span) = match tcx.hir().get_by_hir_id(id) {
34-
Node::Ctor(ctor) => return create_constructor_shim(tcx, id, ctor),
35-
3633
Node::Expr(hir::Expr { node: hir::ExprKind::Closure(_, decl, body_id, _, _), .. })
3734
| Node::Item(hir::Item { node: hir::ItemKind::Fn(decl, _, _, body_id), .. })
3835
| Node::ImplItem(
@@ -234,38 +231,6 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
234231
}
235232
}
236233

237-
fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
238-
ctor_id: hir::HirId,
239-
v: &'tcx hir::VariantData)
240-
-> Body<'tcx>
241-
{
242-
let span = tcx.hir().span_by_hir_id(ctor_id);
243-
if let hir::VariantData::Tuple(ref fields, ctor_id) = *v {
244-
tcx.infer_ctxt().enter(|infcx| {
245-
let mut mir = shim::build_adt_ctor(&infcx, ctor_id, fields, span);
246-
247-
// Convert the `mir::Body` to global types.
248-
let tcx = infcx.tcx.global_tcx();
249-
let mut globalizer = GlobalizeMir {
250-
tcx,
251-
span: mir.span
252-
};
253-
globalizer.visit_body(&mut mir);
254-
let mir = unsafe {
255-
mem::transmute::<Body<'_>, Body<'tcx>>(mir)
256-
};
257-
258-
mir_util::dump_mir(tcx, None, "mir_map", &0,
259-
MirSource::item(tcx.hir().local_def_id_from_hir_id(ctor_id)),
260-
&mir, |_, _| Ok(()) );
261-
262-
mir
263-
})
264-
} else {
265-
span_bug!(span, "attempting to create MIR for non-tuple variant {:?}", v);
266-
}
267-
}
268-
269234
///////////////////////////////////////////////////////////////////////////
270235
// BuildMir -- walks a crate, looking for fn items and methods to build MIR from
271236

src/librustc_mir/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
2222
#![feature(unicode_internals)]
2323
#![feature(step_trait)]
2424
#![feature(slice_concat_ext)]
25+
#![feature(trusted_len)]
2526
#![feature(try_blocks)]
2627

2728
#![recursion_limit="256"]

src/librustc_mir/shim.rs

+51-31
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use rustc::hir;
22
use rustc::hir::def_id::DefId;
3-
use rustc::infer;
43
use rustc::mir::*;
54
use rustc::ty::{self, Ty, TyCtxt};
65
use rustc::ty::layout::VariantIdx;
@@ -21,6 +20,7 @@ use crate::transform::{
2120
};
2221
use crate::util::elaborate_drops::{self, DropElaborator, DropStyle, DropFlagMode};
2322
use crate::util::patch::MirPatch;
23+
use crate::util::expand_aggregate;
2424

2525
pub fn provide(providers: &mut Providers<'_>) {
2626
providers.mir_shims = make_shim;
@@ -842,29 +842,26 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
842842
mir
843843
}
844844

845-
pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
846-
ctor_id: hir::HirId,
847-
fields: &[hir::StructField],
848-
span: Span)
849-
-> Body<'tcx>
850-
{
851-
let tcx = infcx.tcx;
852-
let gcx = tcx.global_tcx();
853-
let def_id = tcx.hir().local_def_id_from_hir_id(ctor_id);
854-
let param_env = gcx.param_env(def_id);
845+
pub fn build_adt_ctor<'gcx>(tcx: TyCtxt<'_, 'gcx, 'gcx>, ctor_id: DefId) -> &'gcx Body<'gcx> {
846+
debug_assert!(tcx.is_constructor(ctor_id));
847+
848+
let span = tcx.hir().span_if_local(ctor_id)
849+
.unwrap_or_else(|| bug!("no span for ctor {:?}", ctor_id));
850+
851+
let param_env = tcx.param_env(ctor_id);
855852

856853
// Normalize the sig.
857-
let sig = gcx.fn_sig(def_id)
854+
let sig = tcx.fn_sig(ctor_id)
858855
.no_bound_vars()
859856
.expect("LBR in ADT constructor signature");
860-
let sig = gcx.normalize_erasing_regions(param_env, sig);
857+
let sig = tcx.normalize_erasing_regions(param_env, sig);
861858

862859
let (adt_def, substs) = match sig.output().sty {
863860
ty::Adt(adt_def, substs) => (adt_def, substs),
864861
_ => bug!("unexpected type for ADT ctor {:?}", sig.output())
865862
};
866863

867-
debug!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id, sig, fields);
864+
debug!("build_ctor: ctor_id={:?} sig={:?}", ctor_id, sig);
868865

869866
let local_decls = local_decls_for_sig(&sig, span);
870867

@@ -873,34 +870,45 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
873870
scope: OUTERMOST_SOURCE_SCOPE
874871
};
875872

876-
let variant_no = if adt_def.is_enum() {
877-
adt_def.variant_index_with_ctor_id(def_id)
873+
let variant_index = if adt_def.is_enum() {
874+
adt_def.variant_index_with_ctor_id(ctor_id)
878875
} else {
879876
VariantIdx::new(0)
880877
};
881878

882-
// return = ADT(arg0, arg1, ...); return
879+
// Generate the following MIR:
880+
//
881+
// (return as Variant).field0 = arg0;
882+
// (return as Variant).field1 = arg1;
883+
//
884+
// return;
885+
debug!("build_ctor: variant_index={:?}", variant_index);
886+
887+
let statements = expand_aggregate(
888+
Place::RETURN_PLACE,
889+
adt_def
890+
.variants[variant_index]
891+
.fields
892+
.iter()
893+
.enumerate()
894+
.map(|(idx, field_def)| (
895+
Operand::Move(Place::Base(PlaceBase::Local(Local::new(idx + 1)))),
896+
field_def.ty(tcx, substs),
897+
)),
898+
AggregateKind::Adt(adt_def, variant_index, substs, None, None),
899+
source_info,
900+
).collect();
901+
883902
let start_block = BasicBlockData {
884-
statements: vec![Statement {
885-
source_info,
886-
kind: StatementKind::Assign(
887-
Place::RETURN_PLACE,
888-
box Rvalue::Aggregate(
889-
box AggregateKind::Adt(adt_def, variant_no, substs, None, None),
890-
(1..sig.inputs().len()+1).map(|i| {
891-
Operand::Move(Place::Base(PlaceBase::Local(Local::new(i))))
892-
}).collect()
893-
)
894-
)
895-
}],
903+
statements,
896904
terminator: Some(Terminator {
897905
source_info,
898906
kind: TerminatorKind::Return,
899907
}),
900908
is_cleanup: false
901909
};
902910

903-
Body::new(
911+
let body = Body::new(
904912
IndexVec::from_elem_n(start_block, 1),
905913
IndexVec::from_elem_n(
906914
SourceScopeData { span: span, parent_scope: None }, 1
@@ -914,5 +922,17 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
914922
vec![],
915923
span,
916924
vec![],
917-
)
925+
);
926+
927+
crate::util::dump_mir(
928+
tcx,
929+
None,
930+
"mir_map",
931+
&0,
932+
crate::transform::MirSource::item(ctor_id),
933+
&body,
934+
|_, _| Ok(()),
935+
);
936+
937+
tcx.arena.alloc(body)
918938
}

src/librustc_mir/transform/deaggregator.rs

+10-58
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use rustc::mir::*;
22
use rustc::ty::TyCtxt;
3-
use rustc::ty::layout::VariantIdx;
4-
use rustc_data_structures::indexed_vec::Idx;
53
use crate::transform::{MirPass, MirSource};
4+
use crate::util::expand_aggregate;
65

76
pub struct Deaggregator;
87

@@ -31,7 +30,7 @@ impl MirPass for Deaggregator {
3130

3231
let stmt = stmt.replace_nop();
3332
let source_info = stmt.source_info;
34-
let (mut lhs, kind, operands) = match stmt.kind {
33+
let (lhs, kind, operands) = match stmt.kind {
3534
StatementKind::Assign(lhs, box rvalue) => {
3635
match rvalue {
3736
Rvalue::Aggregate(kind, operands) => (lhs, kind, operands),
@@ -41,62 +40,15 @@ impl MirPass for Deaggregator {
4140
_ => bug!()
4241
};
4342

44-
let mut set_discriminant = None;
45-
let active_field_index = match *kind {
46-
AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
47-
if adt_def.is_enum() {
48-
set_discriminant = Some(Statement {
49-
kind: StatementKind::SetDiscriminant {
50-
place: lhs.clone(),
51-
variant_index,
52-
},
53-
source_info,
54-
});
55-
lhs = lhs.downcast(adt_def, variant_index);
56-
}
57-
active_field_index
58-
}
59-
AggregateKind::Generator(..) => {
60-
// Right now we only support initializing generators to
61-
// variant 0 (Unresumed).
62-
let variant_index = VariantIdx::new(0);
63-
set_discriminant = Some(Statement {
64-
kind: StatementKind::SetDiscriminant {
65-
place: lhs.clone(),
66-
variant_index,
67-
},
68-
source_info,
69-
});
70-
71-
// Operands are upvars stored on the base place, so no
72-
// downcast is necessary.
73-
74-
None
75-
}
76-
_ => None
77-
};
78-
79-
Some(operands.into_iter().enumerate().map(move |(i, op)| {
80-
let lhs_field = if let AggregateKind::Array(_) = *kind {
81-
// FIXME(eddyb) `offset` should be u64.
82-
let offset = i as u32;
83-
assert_eq!(offset as usize, i);
84-
lhs.clone().elem(ProjectionElem::ConstantIndex {
85-
offset,
86-
// FIXME(eddyb) `min_length` doesn't appear to be used.
87-
min_length: offset + 1,
88-
from_end: false
89-
})
90-
} else {
43+
Some(expand_aggregate(
44+
lhs,
45+
operands.into_iter().map(|op| {
9146
let ty = op.ty(local_decls, tcx);
92-
let field = Field::new(active_field_index.unwrap_or(i));
93-
lhs.clone().field(field, ty)
94-
};
95-
Statement {
96-
source_info,
97-
kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)),
98-
}
99-
}).chain(set_discriminant))
47+
(op, ty)
48+
}),
49+
*kind,
50+
source_info,
51+
))
10052
});
10153
}
10254
}

0 commit comments

Comments
 (0)