@@ -393,29 +393,34 @@ static bool isMemberChainTail(Expr *expr, Expr *parent, MemberChainKind kind) {
393393}
394394
395395static bool isValidForwardReference (ValueDecl *D, DeclContext *DC,
396- ValueDecl ** localDeclAfterUse) {
397- *localDeclAfterUse = nullptr ;
398-
399- // References to variables injected by lldb are always valid.
400- if (isa<VarDecl>(D) && cast<VarDecl>(D)-> isDebuggerVar () )
396+ ValueDecl *& localDeclAfterUse,
397+ bool &shouldUseOuterResults) {
398+ // Only VarDecls require declaration before use.
399+ auto *VD = dyn_cast<VarDecl>(D);
400+ if (!VD )
401401 return true ;
402402
403- // If we find something in the current context, it must be a forward
404- // reference, because otherwise if it was in scope, it would have
405- // been returned by the call to ASTScope::lookupLocalDecls() above.
406- if (D->getDeclContext ()->isLocalContext ()) {
407- do {
408- if (D->getDeclContext () == DC) {
409- *localDeclAfterUse = D;
410- return false ;
411- }
403+ // Non-local and variables injected by lldb are always valid.
404+ auto *varDC = VD->getDeclContext ();
405+ if (!varDC->isLocalContext () || VD->isDebuggerVar ())
406+ return true ;
412407
413- // If we're inside of a 'defer' context, walk up to the parent
414- // and check again. We don't want 'defer' bodies to forward
415- // reference bindings in the immediate outer scope.
416- } while (isa<FuncDecl>(DC) &&
417- cast<FuncDecl>(DC)->isDeferBody () &&
418- (DC = DC->getParent ()));
408+ while (true ) {
409+ if (varDC == DC) {
410+ localDeclAfterUse = VD;
411+ return false ;
412+ }
413+ if (isa<AbstractClosureExpr>(DC) ||
414+ (isa<FuncDecl>(DC) && cast<FuncDecl>(DC)->isDeferBody ())) {
415+ // If we cross a closure, don't context, don't allow falling back to
416+ // an outer result if we have a forward reference. This preserves the
417+ // behavior prior to diagnosing this in Sema.
418+ if (isa<AbstractClosureExpr>(DC))
419+ shouldUseOuterResults = false ;
420+ DC = DC->getParent ();
421+ continue ;
422+ }
423+ break ;
419424 }
420425 return true ;
421426}
@@ -589,19 +594,20 @@ static Expr *resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC,
589594 Lookup = TypeChecker::lookupUnqualified (DC, LookupName, Loc, lookupOptions);
590595
591596 ValueDecl *localDeclAfterUse = nullptr ;
592- AllDeclRefs =
593- findNonMembers (Lookup.innerResults (), UDRE->getRefKind (),
594- /* breakOnMember=*/ true , ResultValues,
595- [&](ValueDecl *D) {
596- return isValidForwardReference (D, DC, &localDeclAfterUse);
597- });
597+ bool shouldUseOuterResults = true ;
598+ AllDeclRefs = findNonMembers (
599+ Lookup.innerResults (), UDRE->getRefKind (),
600+ /* breakOnMember=*/ true , ResultValues, [&](ValueDecl *D) {
601+ return isValidForwardReference (D, DC, localDeclAfterUse,
602+ shouldUseOuterResults);
603+ });
598604
599605 // If local declaration after use is found, check outer results for
600606 // better matching candidates.
601607 if (ResultValues.empty () && localDeclAfterUse) {
602608 auto innerDecl = localDeclAfterUse;
603609 while (localDeclAfterUse) {
604- if (Lookup.outerResults ().empty ()) {
610+ if (!shouldUseOuterResults || Lookup.outerResults ().empty ()) {
605611 Context.Diags .diagnose (Loc, diag::use_local_before_declaration, Name);
606612 Context.Diags .diagnose (innerDecl, diag::decl_declared_here,
607613 localDeclAfterUse);
@@ -611,12 +617,12 @@ static Expr *resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC,
611617 Lookup.shiftDownResults ();
612618 ResultValues.clear ();
613619 localDeclAfterUse = nullptr ;
614- AllDeclRefs =
615- findNonMembers ( Lookup.innerResults (), UDRE->getRefKind (),
616- /* breakOnMember=*/ true , ResultValues,
617- [&](ValueDecl *D) {
618- return isValidForwardReference (D, DC, &localDeclAfterUse );
619- });
620+ AllDeclRefs = findNonMembers (
621+ Lookup.innerResults (), UDRE->getRefKind (),
622+ /* breakOnMember=*/ true , ResultValues, [&](ValueDecl *D) {
623+ return isValidForwardReference (D, DC, localDeclAfterUse,
624+ shouldUseOuterResults );
625+ });
620626 }
621627 }
622628 }
0 commit comments