Fix crash if a user-defined conversion is applied in the middle of a
rewrite of an operator in terms of operator<=>.
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 867615d..afb710e 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -792,6 +792,16 @@
return const_cast<Expr *>(this)->IgnoreImplicit();
}
+ /// Skip past any implicit AST nodes which might surround this expression
+ /// until reaching a fixed point. Same as IgnoreImplicit, except that it
+ /// also skips over implicit calls to constructors and conversion functions.
+ ///
+ /// FIXME: Should IgnoreImplicit do this?
+ Expr *IgnoreImplicitAsWritten() LLVM_READONLY;
+ const Expr *IgnoreImplicitAsWritten() const {
+ return const_cast<Expr *>(this)->IgnoreImplicitAsWritten();
+ }
+
/// Skip past any parentheses which might surround this expression until
/// reaching a fixed point. Skips:
/// * ParenExpr
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 3bc2ea6..c4c8fcf 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -2893,6 +2893,13 @@
return E;
}
+static Expr *IgnoreImplicitAsWrittenSingleStep(Expr *E) {
+ if (auto *ICE = dyn_cast<ImplicitCastExpr>(E))
+ return ICE->getSubExprAsWritten();
+
+ return IgnoreImplicitSingleStep(E);
+}
+
static Expr *IgnoreParensSingleStep(Expr *E) {
if (auto *PE = dyn_cast<ParenExpr>(E))
return PE->getSubExpr();
@@ -2972,6 +2979,10 @@
return IgnoreExprNodes(this, IgnoreImplicitSingleStep);
}
+Expr *Expr::IgnoreImplicitAsWritten() {
+ return IgnoreExprNodes(this, IgnoreImplicitAsWrittenSingleStep);
+}
+
Expr *Expr::IgnoreParens() {
return IgnoreExprNodes(this, IgnoreParensSingleStep);
}
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index bef181e..deb7682 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -107,7 +107,7 @@
return Result;
// Otherwise, we expect a <=> to now be on the LHS.
- E = Result.LHS->IgnoreImplicit();
+ E = Result.LHS->IgnoreImplicitAsWritten();
if (auto *BO = dyn_cast<BinaryOperator>(E)) {
assert(BO->getOpcode() == BO_Cmp);
Result.LHS = BO->getLHS();
diff --git a/clang/test/SemaCXX/compare-cxx2a.cpp b/clang/test/SemaCXX/compare-cxx2a.cpp
index 28854a7..1aca2dd 100644
--- a/clang/test/SemaCXX/compare-cxx2a.cpp
+++ b/clang/test/SemaCXX/compare-cxx2a.cpp
@@ -361,6 +361,11 @@
}
}
+struct X {
+ constexpr const Conv<int, -1> operator<=>(X) { return {}; }
+};
+static_assert(X() < X());
+
} // namespace TestUserDefinedConvSeq
void test_array_conv() {