@@ -106,23 +106,26 @@ impl LoanContext {
106
106
cat_discr( base, _) => {
107
107
self . loan ( base, req_mutbl)
108
108
}
109
- cat_comp( cmt_base, comp_field( * ) ) |
110
- cat_comp( cmt_base, comp_index( * ) ) |
111
- cat_comp( cmt_base, comp_tuple) => {
109
+ cat_comp( cmt_base, comp_field( _, m) ) |
110
+ cat_comp( cmt_base, comp_index( _, m) ) => {
112
111
// For most components, the type of the embedded data is
113
112
// stable. Therefore, the base structure need only be
114
113
// const---unless the component must be immutable. In
115
114
// that case, it must also be embedded in an immutable
116
115
// location, or else the whole structure could be
117
116
// overwritten and the component along with it.
118
- self . loan_stable_comp ( cmt, cmt_base, req_mutbl)
117
+ self . loan_stable_comp ( cmt, cmt_base, req_mutbl, m)
118
+ }
119
+ cat_comp( cmt_base, comp_tuple) => {
120
+ // As above.
121
+ self . loan_stable_comp ( cmt, cmt_base, req_mutbl, m_imm)
119
122
}
120
123
cat_comp( cmt_base, comp_variant( enum_did) ) => {
121
124
// For enums, the memory is unstable if there are multiple
122
125
// variants, because if the enum value is overwritten then
123
126
// the memory changes type.
124
127
if ty:: enum_is_univariant ( self . bccx . tcx , enum_did) {
125
- self . loan_stable_comp ( cmt, cmt_base, req_mutbl)
128
+ self . loan_stable_comp ( cmt, cmt_base, req_mutbl, m_imm )
126
129
} else {
127
130
self . loan_unstable_deref ( cmt, cmt_base, req_mutbl)
128
131
}
@@ -150,10 +153,59 @@ impl LoanContext {
150
153
fn loan_stable_comp ( & self ,
151
154
cmt : cmt ,
152
155
cmt_base : cmt ,
153
- req_mutbl : ast:: mutability ) -> bckres < ( ) > {
154
- let base_mutbl = match req_mutbl {
155
- m_imm => m_imm,
156
- m_const | m_mutbl => m_const
156
+ req_mutbl : ast:: mutability ,
157
+ comp_mutbl : ast:: mutability ) -> bckres < ( ) > {
158
+ // Determine the mutability that the base component must have,
159
+ // given the required mutability of the pointer (`req_mutbl`)
160
+ // and the declared mutability of the component (`comp_mutbl`).
161
+ // This is surprisingly subtle.
162
+ //
163
+ // Note that the *declared* mutability of the component is not
164
+ // necessarily the same as cmt.mutbl, since a component
165
+ // declared as immutable but embedded in a mutable context
166
+ // becomes mutable. It's best to think of comp_mutbl as being
167
+ // either MUTABLE or DEFAULT, not MUTABLE or IMMUTABLE. We
168
+ // should really patch up the AST to reflect this distinction.
169
+ //
170
+ // Let's consider the cases below:
171
+ //
172
+ // 1. mut required, mut declared: In this case, the base
173
+ // component must merely be const. The reason is that it
174
+ // does not matter if the base component is borrowed as
175
+ // mutable or immutable, as the mutability of the base
176
+ // component is overridden in the field declaration itself
177
+ // (see `compile-fail/borrowck-mut-field-imm-base.rs`)
178
+ //
179
+ // 2. mut required, imm declared: This would only be legal if
180
+ // the component is embeded in a mutable context. However,
181
+ // we detect mismatches between the mutability of the value
182
+ // as a whole and the required mutability in `issue_loan()`
183
+ // above. In any case, presuming that the component IS
184
+ // embedded in a mutable context, both the component and
185
+ // the base must be loaned as MUTABLE. This is to ensure
186
+ // that there is no loan of the base as IMMUTABLE, which
187
+ // would imply that the component must be IMMUTABLE too
188
+ // (see `compile-fail/borrowck-imm-field-imm-base.rs`).
189
+ //
190
+ // 3. mut required, const declared: this shouldn't really be
191
+ // possible, since I don't think you can declare a const
192
+ // field, but I guess if we DID permit such a declaration
193
+ // it would be equivalent to the case above?
194
+ //
195
+ // 4. imm required, * declared: In this case, the base must be
196
+ // immutable. This is true regardless of what was declared
197
+ // for this subcomponent, this if the base is mutable, the
198
+ // subcomponent must be mutable.
199
+ // (see `compile-fail/borrowck-imm-field-mut-base.rs`).
200
+ //
201
+ // 5. const required, * declared: In this case, the base need
202
+ // only be const, since we don't ultimately care whether
203
+ // the subcomponent is mutable or not.
204
+ let base_mutbl = match ( req_mutbl, comp_mutbl) {
205
+ ( m_mutbl, m_mutbl) => m_const, // (1)
206
+ ( m_mutbl, _) => m_mutbl, // (2, 3)
207
+ ( m_imm, _) => m_imm, // (4)
208
+ ( m_const, _) => m_const // (5)
157
209
} ;
158
210
159
211
do self. loan ( cmt_base, base_mutbl) . chain |_ok| {
0 commit comments