[all-commits] [llvm/llvm-project] 27181c: Support: Add Expected<T>::moveInto() to avoid extr...

Duncan P. N. Exon Smith via All-commits all-commits at lists.llvm.org
Fri Oct 22 11:47:31 PDT 2021


  Branch: refs/heads/main
  Home:   https://github.com/llvm/llvm-project
  Commit: 27181cad0d4e48eac822aaccf52b612f29eeff73
      https://github.com/llvm/llvm-project/commit/27181cad0d4e48eac822aaccf52b612f29eeff73
  Author: Duncan P. N. Exon Smith <dexonsmith at apple.com>
  Date:   2021-10-22 (Fri, 22 Oct 2021)

  Changed paths:
    M llvm/docs/ProgrammersManual.rst
    M llvm/include/llvm/Support/Error.h
    M llvm/unittests/Support/ErrorTest.cpp

  Log Message:
  -----------
  Support: Add Expected<T>::moveInto() to avoid extra names

Expected<T>::moveInto() takes as an out parameter any `OtherT&` that's
assignable from `T&&`. It moves any stored value before returning
takeError().

Since moveInto() consumes both the Error and the value, it's only
anticipated that we'd use call it on temporaries/rvalues, with naming
the Expected first likely to be an anti-pattern of sorts (either you
want to deal with both at the same time, or you don't). As such,
starting it out as `&&`-qualified... but it'd probably be fine to drop
that if there's a good use case for lvalues that appears.

There are two common patterns that moveInto() cleans up:
```
  // If the variable is new:
  Expected<std::unique_ptr<int>> ExpectedP = makePointer();
  if (!ExpectedP)
    return ExpectedP.takeError();
  std::unique_ptr<int> P = std::move(*ExpectedP);

  // If the target variable already exists:
  if (Expected<T> ExpectedP = makePointer())
    P = std::move(*ExpectedP);
  else
    return ExpectedP.takeError();
```
moveInto() takes less typing and avoids needing to name (or leak into
the scope) an extra variable.
```
  // If the variable is new:
  std::unique_ptr<int> P;
  if (Error E = makePointer().moveInto(P))
    return E;

  // If the target variable already exists:
  if (Error E = makePointer().moveInto(P))
    return E;
```

It also seems useful for unit tests, to log errors (but continue) when
there's an unexpected failure. E.g.:
```
  // Crash on error, or undefined in non-asserts builds.
  std::unique_ptr<MemoryBuffer> MB = cantFail(makeMemoryBuffer());

  // Avoid crashing on error without moveInto() :(.
  Expected<std::unique_ptr<MemoryBuffer>>
      ExpectedMB = makeMemoryBuffer();
  ASSERT_THAT_ERROR(ExpectedMB.takeError(), Succeeded());
  std::unique_ptr<MemoryBuffer> MB = std::move(ExpectedMB);

  // Avoid crashing on error with moveInto() :).
  std::unique_ptr<MemoryBuffer> MB;
  ASSERT_THAT_ERROR(makeMemoryBuffer().moveInto(MB), Succeeded());
```

Differential Revision: https://reviews.llvm.org/D112278




More information about the All-commits mailing list