Repository: llvm/llvm-project
File: clang/lib/Interpreter/IncrementalParser.cpp (C++)

Code before:
      bool RemoveAll = true;
      for (NamedDecl *D : R) {
        if (D->getTranslationUnitDecl() == MostRecentTU)
          NamedDeclsToRemove.push_back(D);
        else
          RemoveAll = false;
      }
      if (LLVM_LIKELY(RemoveAll)) {
        Map->erase(Key);
      } else {
        for (NamedDecl *D : NamedDeclsToRemove)
          List.remove(D);
      }
    }
  }

  auto *ECCD = S.getASTContext().getExternCContextDecl();
  if (auto *Map = ECCD->getPrimaryContext()->getLookupPtr()) {
    for (auto &&[Key, List] : *Map) {
      DeclContextLookupResult R = List.getLookupResult();
      std::vector<NamedDecl *> NamedDeclsToRemove;
      for (NamedDecl *D : R) {
        // Implicitly generated C decl is not attached to the current TU but
        // lexically attached to the recent TU, so we need to check the lexical
        // context.
        DeclContext *LDC = D->getLexicalDeclContext();
        while (LDC && !isa<TranslationUnitDecl>(LDC)) {
          LDC = LDC->getLexicalParent();
        }
        TranslationUnitDecl *TopTU = cast_or_null<TranslationUnitDecl>(LDC);
        if (TopTU == MostRecentTU)
          NamedDeclsToRemove.push_back(D);
      }
      for (NamedDecl *D : NamedDeclsToRemove) {
        List.remove(D);
        S.IdResolver.RemoveDecl(D);
      }
    }
  }

  // FIXME: We should de-allocate MostRecentTU
  for (Decl *D : MostRecentTU->decls()) {
    auto *ND = dyn_cast<NamedDecl>(D);
    if (!ND || ND->getDeclName().isEmpty())
      continue;
    // Check if we need to clean up the IdResolver chain.
    if (ND->getDeclName().getFETokenInfo() && !D->getLangOpts().ObjC &&
        !D->getLangOpts().CPlusPlus)
      S.IdResolver.RemoveDecl(ND);
  }
}

Review comment (suggestion):
That part makes me uncomfortable. We try to iterate over the lookup candidates in this case. However, is there a route from the `MostRecentTU` to the declaration that was created. Isn't it part from the DeclContext part of the object? If there is no way to get it, then there is some logical flow in either clang, where the implicit declaration creation does not respect the active TU or something else.

Code after:
      std::vector<NamedDecl *> NamedDeclsToRemove;
      bool RemoveAll = true;
      for (NamedDecl *D : R) {
        if (D->getTranslationUnitDecl() == MostRecentTU)
          NamedDeclsToRemove.push_back(D);
        else
          RemoveAll = false;
      }
      if (LLVM_LIKELY(RemoveAll)) {
        Map->erase(Key);
      } else {
        for (NamedDecl *D : NamedDeclsToRemove)
          List.remove(D);
      }
    }
  }

  ExternCContextDecl *ECCD = S.getASTContext().getExternCContextDecl();
  if (StoredDeclsMap *Map = ECCD->getPrimaryContext()->getLookupPtr()) {
    for (auto &&[Key, List] : *Map) {
      DeclContextLookupResult R = List.getLookupResult();
      llvm::SmallVector<NamedDecl *, 4> NamedDeclsToRemove;
      for (NamedDecl *D : R) {
        // Implicitly generated C decl is not attached to the current TU but
        // lexically attached to the recent TU, so we need to check the lexical
        // context.
        DeclContext *LDC = D->getLexicalDeclContext();
        while (LDC && !isa<TranslationUnitDecl>(LDC))
          LDC = LDC->getLexicalParent();
        TranslationUnitDecl *TopTU = cast_or_null<TranslationUnitDecl>(LDC);
        if (TopTU == MostRecentTU)
          NamedDeclsToRemove.push_back(D);
      }
      for (NamedDecl *D : NamedDeclsToRemove) {
        List.remove(D);
        S.IdResolver.RemoveDecl(D);
      }
    }
  }

  // FIXME: We should de-allocate MostRecentTU
  for (Decl *D : MostRecentTU->decls()) {
    auto *ND = dyn_cast<NamedDecl>(D);
    if (!ND || ND->getDeclName().isEmpty())
      continue;
    // Check if we need to clean up the IdResolver chain.
    if (ND->getDeclName().getFETokenInfo() && !D->getLangOpts().ObjC &&
        !D->getLangOpts().CPlusPlus)
      S.IdResolver.RemoveDecl(ND);
  }
}