Before this patch, the dependence of CallExpr was only computed in the
constructor, the dependence bits might not reflect truth -- some arguments might
be not set (nullptr) during this time, e.g. CXXDefaultArgExpr will be set via
the setArg method in the later parsing stage, so we need to recompute the
dependence bits.
Details
- Reviewers
sammccall
Diff Detail
- Repository
- rG LLVM Github Monorepo
Unit Tests
Event Timeline
This seems correct but it also seems like it makes setting all the args of a CallExpr into a quadratic operation.
e.g. ConvertArgumentForCall and BuildResolvedCallExpr in SemaExpr seem to do this (not just missing/changed args) and are probably on common code paths.
It's hard to see how to fix this without touching the API or being fiddly with the dependence bits (e.g. setArg only needs to rescan all args if we're removing at least one dep bit vs the old value, which should be rare).
Also this function just calls through to the (mutable) getArgs() which returns a mutable Expr**. This allows mutating args, bypassing setArg(), and ISTM there are cases where this really happens e.g. in TreeTransform::TransformCallExpr.
Again, it seems like changing the API might be the answer here: we can separate out the getArgs() which only need read access from those that are doing something tricky.
A tempting API would be something like getMutableArgs() -> some smart object that exposes the mutable arg array and also recalculates dependence when destroyed.
I guess the way to make this ergonomic is to actually inherit from MutableArrayRef, like:
class CallExpr::MutableArgs : public MutableArrayRef<Expr> { CallExpr *Parent; public: // Note that "slicing" copy to MutableArrayRef is still allowed. MutableArgs(const MutableArgs&) = delete; MutableArgs &operator=(const MutableArgs&) = delete; MutableArgs(MutableArgs&&) = delete; MutableArgs &operator=(MutableArgs&&) = delete; ~MutableArgs() { Parent->recomputeDependence(); } };
I'm not sure if you see this as overengineering.
I think I can also live with adding explicit recomputeDependence() calls in the right places, and slapping a warning on setArg() that it might be needed.
But i'm not sure that making setArg() implicitly recalculate is a happy in-between point. WDYT?
sorry for the delay, I lost the track.
I think I can also live with adding explicit recomputeDependence() calls in the right places, and slapping a warning on setArg() that it might be needed.
I'm inclined with this option.
As you mentioned, there are two major places (ConvertArgumentForCall and BuildResolvedCallExpr in SemaExpr) calling setArg, and it is trivial to update them.
There are a lot of setArg usage in SemaChecking.cpp, but I think we're not interested to them -- because there are invalid checks before calling setArg and we mostly care about the error-bit.
clang/include/clang/AST/Expr.h | ||
---|---|---|
2991 | by calling computeDependence() |
by calling computeDependence()