[PATCH] D106862: [clang][modules] Avoid creating partial FullSourceLoc for explicit modules imports

Jan Svoboda via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 30 04:52:54 PDT 2021


jansvoboda11 requested review of this revision.
jansvoboda11 added a comment.

I investigated this a bit more.

What previously lead me to believe that `SourceLoc::ID` is being modified from the outside was the way it's declared right after some `friend`s:

  class SourceLocation {
    friend class ASTReader;
    friend class ASTWriter;
    friend class SourceManager;
    friend struct llvm::FoldingSetTrait<SourceLocation>;
  
  public:
    using UIntTy = uint32_t;
    using IntTy = int32_t;
  
  private:
    UIntTy ID = 0;

I looked up the actual writes to `ID` and they only occur in the `SourceLocation` factory functions, for example:

  SourceLocation getLocWithOffset(IntTy Offset) const {
    assert(((getOffset()+Offset) & MacroIDBit) == 0 && "offset overflow");
    SourceLocation L;
    L.ID = ID+Offset;
    return L;
  }

Theoretically there's nothing preventing the friends from modifying the field as well, but that's not being abused at this moment.

This means that if the `FullSourceLoc(SourceLocation, SourceManager &)` constructor was to be called with an invalid `SourceLocation`, it would stay invalid for the whole lifetime of `FullSourceLoc`.

---

So if we really expect <https://reviews.llvm.org/D31709?id=95541#inline-279799> `FullSourceLoc` to always uphold this invariant: `(SrcMgr != nullptr) == isValid()`, we should be able to replace this assertion:

  bool hasManager() const {
      bool hasSrcMgr =  SrcMgr != nullptr;
      assert(hasSrcMgr == isValid() && "FullSourceLoc has location but no manager");
      return hasSrcMgr;
  }

with this one:

  explicit FullSourceLoc(SourceLocation Loc, const SourceManager &SM)
      : SourceLocation(Loc), SrcMgr(&SM) {
    assert(isValid() && "FullSourceLoc has manager but no location");
  }

That way, we can catch any future misuse of `FullSourceLoc` much earlier.

---

But: I think the intention for `FullSourceLoc` has never been to uphold that invariant:

- `FullSourceLoc` is being constructed without clients ensuring the validity of the `SourceLoc`.
  - Moving the assertion into the constructor and running tests confirmed `FullSourceLoc` is indeed being constructed with invalid `SourceLocation` (and valid `SourceManager`).
- The clients also never check `isValid()` before calling `hasManager()` to avoid the assertion in `hasManager()`, which is odd.
  - I think the assertion in `hasManager` has never been hit before simply by pure luck.

---

Considering that `FullSourceLoc` has been around since 2007 and the assertion was just added in 2017, I think the correct thing to do here is to remove the assertion and properly document that `FullSourceLoc` does not uphold any invariants.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106862/new/

https://reviews.llvm.org/D106862



More information about the cfe-commits mailing list