@@ -238,37 +238,51 @@ private struct DiagnoseDependence {
238238
239239 // Identify the escaping variable.
240240 let escapingVar = LifetimeVariable ( dependent: operand. value, context)
241- let varName = escapingVar. name
242- if let varName {
243- diagnose ( escapingVar. sourceLoc, . lifetime_variable_outside_scope,
244- varName)
241+ if let varDecl = escapingVar. varDecl {
242+ // Use the variable location, not the access location.
243+ diagnose ( varDecl. nameLoc, . lifetime_variable_outside_scope, escapingVar. name ?? " " )
244+ } else if let sourceLoc = escapingVar. sourceLoc {
245+ diagnose ( sourceLoc, . lifetime_value_outside_scope)
245246 } else {
246- diagnose ( escapingVar. sourceLoc, . lifetime_value_outside_scope)
247+ // Always raise an error even if we can't find a source location.
248+ let sourceLoc = function. location. sourceLoc
249+ if let accessorKind = escapingVar. accessorKind {
250+ diagnose ( sourceLoc, . lifetime_value_outside_accessor, accessorKind)
251+ } else {
252+ // Thunks do not have a source location, but we try to use the function location anyway.
253+ let thunkSelect = dependence. function. thunkKind == . noThunk ? 0 : 1
254+ diagnose ( sourceLoc, . lifetime_value_outside_thunk, thunkSelect, function. name)
255+ }
247256 }
248257 reportScope ( )
249258 // Identify the use point.
250- let userSourceLoc = operand. instruction. location. sourceLoc
251- diagnose ( userSourceLoc, diagID)
259+ if let userSourceLoc = operand. instruction. location. sourceLoc {
260+ diagnose ( userSourceLoc, diagID)
261+ }
252262 }
253263
254- // Identify the dependence scope.
264+ // Identify the dependence scope. If no source location is found, bypass this diagnostic.
255265 func reportScope( ) {
256- if case let . access( beginAccess) = dependence. scope {
257- let parentVar = LifetimeVariable ( dependent: beginAccess, context)
258- if let sourceLoc = beginAccess. location. sourceLoc ?? parentVar. sourceLoc {
259- diagnose ( sourceLoc, . lifetime_outside_scope_access,
260- parentVar. name ?? " " )
261- }
266+ let parentVar = LifetimeVariable ( dependent: dependence. parentValue, context)
267+ // First check if the dependency is limited to an access scope. If the access has no source location then
268+ // fall-through to report possible dependence on an argument.
269+ if parentVar. isAccessScope, let accessLoc = parentVar. sourceLoc {
270+ diagnose ( accessLoc, . lifetime_outside_scope_access, parentVar. name ?? " " )
262271 return
263272 }
264- if let arg = dependence. parentValue as? Argument ,
265- let varDecl = arg. varDecl,
266- let sourceLoc = arg. sourceLoc {
267- diagnose ( sourceLoc, . lifetime_outside_scope_argument,
268- varDecl. userFacingName)
273+ // If the argument does not have a source location (e.g. a synthesized accessor), report the function location. The
274+ // function's source location is sufficient for argument diagnostics, but if the function has no location, don't
275+ // report any scope.
276+ if parentVar. isArgument, let argLoc = parentVar. sourceLoc ?? function. location. sourceLoc {
277+ if let parentName = parentVar. name {
278+ diagnose ( argLoc, . lifetime_outside_scope_argument, parentName)
279+ } else {
280+ diagnose ( argLoc, . lifetime_outside_scope_synthesized_argument, parentVar. accessorKind ?? function. name)
281+ }
269282 return
270283 }
271- let parentVar = LifetimeVariable ( dependent: dependence. parentValue, context)
284+ // Now diagnose dependencies on regular variable and value scopes.
285+ // Thunks do not have a function location, so any scopes inside the thunk will be ignored.
272286 if let parentLoc = parentVar. sourceLoc {
273287 if let parentName = parentVar. name {
274288 diagnose ( parentLoc, . lifetime_outside_scope_variable, parentName)
@@ -282,24 +296,34 @@ private struct DiagnoseDependence {
282296// Identify a best-effort variable declaration based on a defining SIL
283297// value or any lifetime dependent use of that SIL value.
284298private struct LifetimeVariable {
285- var varDecl : VarDecl ?
286- var sourceLoc : SourceLoc ?
299+ var varDecl : VarDecl ? = nil
300+ var sourceLoc : SourceLoc ? = nil
301+ var isArgument : Bool = false
302+ var isAccessScope : Bool = false
303+ var accessorKind : String ?
304+ var thunkKind : Function . ThunkKind = . noThunk
287305
288306 var name : StringRef ? {
289307 return varDecl? . userFacingName
290308 }
291309
292310 init ( dependent value: Value , _ context: some Context ) {
293- if value. type. isAddress {
294- self = Self ( accessBase: value. accessBase, context)
311+ guard let introducer = getFirstVariableIntroducer ( of: value, context) else {
295312 return
296313 }
297- if let firstIntroducer = getFirstVariableIntroducer ( of: value, context) {
298- self = Self ( introducer: firstIntroducer)
314+ if introducer. type. isAddress {
315+ if let beginAccess = introducer as? BeginAccessInst {
316+ // Recurse through beginAccess to find the variable introducer rather than the variable access.
317+ self = . init( dependent: beginAccess. address, context)
318+ self . isAccessScope = true
319+ // However, remember source location of the innermost access.
320+ self . sourceLoc = beginAccess. location. sourceLoc ?? self . sourceLoc
321+ return
322+ }
323+ self = . init( accessBase: introducer. accessBase, context)
299324 return
300325 }
301- self . varDecl = nil
302- self . sourceLoc = nil
326+ self = Self ( introducer: introducer, context)
303327 }
304328
305329 private func getFirstVariableIntroducer( of value: Value , _ context: some Context ) -> Value ? {
@@ -313,15 +337,21 @@ private struct LifetimeVariable {
313337 return introducer
314338 }
315339
316- private init ( introducer: Value ) {
340+ private init ( introducer: Value , _ context : some Context ) {
317341 if let arg = introducer as? Argument {
318342 self . varDecl = arg. varDecl
319- } else {
320- self . sourceLoc = introducer . definingInstruction ? . location . sourceLoc
321- self . varDecl = introducer . definingInstruction ? . findVarDecl ( )
343+ self . sourceLoc = arg . sourceLoc
344+ self . isArgument = true
345+ return
322346 }
323- if let varDecl {
324- sourceLoc = varDecl. nameLoc
347+ if let varDecl = introducer. definingInstruction? . findVarDecl ( ) {
348+ self . varDecl = varDecl
349+ self . sourceLoc = varDecl. nameLoc
350+ } else if let sourceLoc = introducer. definingInstruction? . location. sourceLoc {
351+ self . sourceLoc = sourceLoc
352+ } else {
353+ self . accessorKind = introducer. parentFunction. accessorKindName
354+ self . thunkKind = introducer. parentFunction. thunkKind
325355 }
326356 }
327357
@@ -335,32 +365,27 @@ private struct LifetimeVariable {
335365 // never be produced by one of these, except when it is redundant with the `alloc_box` VarDecl. It does not seem
336366 // possible for a box to be moved/borrowed directly into another variable's box. Reassignment always loads/stores
337367 // the value.
338- self = Self ( introducer: projectBox. box. referenceRoot)
368+ self = . init ( introducer: projectBox. box. referenceRoot, context )
339369 case . stack( let allocStack) :
340- self = Self ( introducer: allocStack)
370+ self = . init ( introducer: allocStack, context )
341371 case . global( let globalVar) :
342372 self . varDecl = globalVar. varDecl
343373 self . sourceLoc = varDecl? . nameLoc
344374 case . class( let refAddr) :
345- self . varDecl = refAddr. varDecl
346- self . sourceLoc = refAddr. location. sourceLoc
375+ self = . init( introducer: refAddr, context)
347376 case . tail( let refTail) :
348- self = Self ( introducer: refTail. instance)
377+ self = . init ( introducer: refTail. instance, context )
349378 case . argument( let arg) :
350- self . varDecl = arg. varDecl
351- self . sourceLoc = arg. sourceLoc
379+ self = . init( introducer: arg, context)
352380 case . yield( let result) :
353381 // TODO: bridge VarDecl for FunctionConvention.Yields
354- self . varDecl = nil
355- self . sourceLoc = result. parentInstruction. location. sourceLoc
382+ self = . init( introducer: result, context)
356383 case . storeBorrow( let sb) :
357384 self = . init( dependent: sb. source, context)
358385 case . pointer( let ptrToAddr) :
359- self . varDecl = nil
360- self . sourceLoc = ptrToAddr. location. sourceLoc
386+ self = . init( introducer: ptrToAddr, context)
361387 case . index, . unidentified:
362- self . varDecl = nil
363- self . sourceLoc = nil
388+ break
364389 }
365390 }
366391}
0 commit comments