Skip to content

Commit 276d214

Browse files
kimgrAaronBallman
authored andcommitted
Generalize and harmonize sub-expression traversal
CastExpr::getSubExprAsWritten and getConversionFunction used to have disparate implementations to traverse the sub-expression chain and skip so-called "implicit temporaries" (which are really implicit nodes added by Sema to represent semantic details in the AST). There's some friction in these algorithms that makes it hard to extend and change them: * skipImplicitTemporary is order-dependent; it can skip a CXXBindTemporaryExpr nested inside a MaterializeTemporaryExpr, but not vice versa * skipImplicitTemporary only runs one pass, it does not traverse multiple nested sequences of MTE/CBTE/MTE/CBTE, for example Both of these weaknesses are void at this point, because this kind of out-of-order multi-level nesting does not exist in the current AST. Adding a new implicit expression to skip exacerbates the problem, however, since a node X might show up in any and all locations between the existing. Thus; * Harmonize the form of getSubExprAsWritten and getConversionFunction so they both use a for loop * Use the IgnoreExprNodes machinery to skip multiple nodes * Rename skipImplicitTemporary to ignoreImplicitSemaNodes to generalize * Update ignoreImplicitSemaNodes so it only skips one level per call, to mirror existing Ignore functions and work better with IgnoreExprNodes This is a functional change, but one without visible effect.
1 parent 892c104 commit 276d214

File tree

1 file changed

+21
-24
lines changed

1 file changed

+21
-24
lines changed

clang/lib/AST/Expr.cpp

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1862,51 +1862,48 @@ const char *CastExpr::getCastKindName(CastKind CK) {
18621862
}
18631863

18641864
namespace {
1865-
const Expr *skipImplicitTemporary(const Expr *E) {
1866-
// Skip through reference binding to temporary.
1867-
if (auto *Materialize = dyn_cast<MaterializeTemporaryExpr>(E))
1868-
E = Materialize->getSubExpr();
1865+
// Skip over implicit nodes produced as part of semantic analysis.
1866+
// Designed for use with IgnoreExprNodes.
1867+
Expr *ignoreImplicitSemaNodes(Expr *E) {
1868+
if (auto *Materialize = dyn_cast<MaterializeTemporaryExpr>(E))
1869+
return Materialize->getSubExpr();
18691870

1870-
// Skip any temporary bindings; they're implicit.
1871-
if (auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E))
1872-
E = Binder->getSubExpr();
1871+
if (auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E))
1872+
return Binder->getSubExpr();
18731873

1874-
return E;
1875-
}
1874+
return E;
18761875
}
1876+
} // namespace
18771877

18781878
Expr *CastExpr::getSubExprAsWritten() {
18791879
const Expr *SubExpr = nullptr;
1880-
const CastExpr *E = this;
1881-
do {
1882-
SubExpr = skipImplicitTemporary(E->getSubExpr());
1880+
1881+
for (const CastExpr *E = this; E; E = dyn_cast<ImplicitCastExpr>(SubExpr)) {
1882+
SubExpr = IgnoreExprNodes(E->getSubExpr(), ignoreImplicitSemaNodes);
18831883

18841884
// Conversions by constructor and conversion functions have a
18851885
// subexpression describing the call; strip it off.
1886-
if (E->getCastKind() == CK_ConstructorConversion)
1887-
SubExpr =
1888-
skipImplicitTemporary(cast<CXXConstructExpr>(SubExpr->IgnoreImplicit())->getArg(0));
1889-
else if (E->getCastKind() == CK_UserDefinedConversion) {
1886+
if (E->getCastKind() == CK_ConstructorConversion) {
1887+
SubExpr = IgnoreExprNodes(
1888+
cast<CXXConstructExpr>(SubExpr->IgnoreImplicit())->getArg(0),
1889+
ignoreImplicitSemaNodes);
1890+
} else if (E->getCastKind() == CK_UserDefinedConversion) {
18901891
SubExpr = SubExpr->IgnoreImplicit();
1891-
assert((isa<CXXMemberCallExpr>(SubExpr) ||
1892-
isa<BlockExpr>(SubExpr)) &&
1892+
assert((isa<CXXMemberCallExpr>(SubExpr) || isa<BlockExpr>(SubExpr)) &&
18931893
"Unexpected SubExpr for CK_UserDefinedConversion.");
18941894
if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SubExpr))
18951895
SubExpr = MCE->getImplicitObjectArgument();
18961896
}
1897+
}
18971898

1898-
// If the subexpression we're left with is an implicit cast, look
1899-
// through that, too.
1900-
} while ((E = dyn_cast<ImplicitCastExpr>(SubExpr)));
1901-
1902-
return const_cast<Expr*>(SubExpr);
1899+
return const_cast<Expr *>(SubExpr);
19031900
}
19041901

19051902
NamedDecl *CastExpr::getConversionFunction() const {
19061903
const Expr *SubExpr = nullptr;
19071904

19081905
for (const CastExpr *E = this; E; E = dyn_cast<ImplicitCastExpr>(SubExpr)) {
1909-
SubExpr = skipImplicitTemporary(E->getSubExpr());
1906+
SubExpr = IgnoreExprNodes(E->getSubExpr(), ignoreImplicitSemaNodes);
19101907

19111908
if (E->getCastKind() == CK_ConstructorConversion)
19121909
return cast<CXXConstructExpr>(SubExpr)->getConstructor();

0 commit comments

Comments
 (0)