Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit ea521aa

Browse files
committed
[c++20] Add CXXRewrittenBinaryOperator to represent a comparison
operator that is rewritten as a call to multiple other operators. No functionality change yet: nothing creates these expressions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@375305 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 3b03365 commit ea521aa

23 files changed

+295
-0
lines changed

include/clang/AST/ExprCXX.h

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,96 @@ class CXXMemberCallExpr final : public CallExpr {
220220
}
221221
};
222222

223+
/// A rewritten comparison expression that was originally written using
224+
/// operator syntax.
225+
///
226+
/// In C++20, the following rewrites are performed:
227+
/// - <tt>a == b</tt> -> <tt>b == a</tt>
228+
/// - <tt>a != b</tt> -> <tt>!(a == b)</tt>
229+
/// - <tt>a != b</tt> -> <tt>!(b == a)</tt>
230+
/// - For \c \@ in \c <, \c <=, \c >, \c >=, \c <=>:
231+
/// - <tt>a @ b<tt> -> <tt>(a <=> b) @ 0</tt>
232+
/// - <tt>a @ b<tt> -> <tt>0 @ (b <=> a)</tt>
233+
///
234+
/// This expression provides access to both the original syntax and the
235+
/// rewritten expression.
236+
///
237+
/// Note that the rewritten calls to \c ==, \c <=>, and \c \@ are typically
238+
/// \c CXXOperatorCallExprs, but could theoretically be \c BinaryOperators.
239+
class CXXRewrittenBinaryOperator : public Expr {
240+
friend class ASTStmtReader;
241+
242+
/// The rewritten semantic form.
243+
Stmt *SemanticForm;
244+
245+
public:
246+
CXXRewrittenBinaryOperator(Expr *SemanticForm, bool IsReversed)
247+
: Expr(CXXRewrittenBinaryOperatorClass, SemanticForm->getType(),
248+
SemanticForm->getValueKind(), SemanticForm->getObjectKind(),
249+
SemanticForm->isTypeDependent(), SemanticForm->isValueDependent(),
250+
SemanticForm->isInstantiationDependent(),
251+
SemanticForm->containsUnexpandedParameterPack()),
252+
SemanticForm(SemanticForm) {
253+
CXXRewrittenBinaryOperatorBits.IsReversed = IsReversed;
254+
}
255+
CXXRewrittenBinaryOperator(EmptyShell Empty)
256+
: Expr(CXXRewrittenBinaryOperatorClass, Empty), SemanticForm() {}
257+
258+
/// Get an equivalent semantic form for this expression.
259+
Expr *getSemanticForm() { return cast<Expr>(SemanticForm); }
260+
const Expr *getSemanticForm() const { return cast<Expr>(SemanticForm); }
261+
262+
struct DecomposedForm {
263+
/// The original opcode, prior to rewriting.
264+
BinaryOperatorKind Opcode;
265+
/// The original left-hand side.
266+
const Expr *LHS;
267+
/// The original right-hand side.
268+
const Expr *RHS;
269+
/// The inner \c == or \c <=> operator expression.
270+
const Expr *InnerBinOp;
271+
};
272+
273+
/// Decompose this operator into its syntactic form.
274+
DecomposedForm getDecomposedForm() const LLVM_READONLY;
275+
276+
/// Determine whether this expression was rewritten in reverse form.
277+
bool isReversed() const { return CXXRewrittenBinaryOperatorBits.IsReversed; }
278+
279+
BinaryOperatorKind getOperator() const { return getDecomposedForm().Opcode; }
280+
const Expr *getLHS() const { return getDecomposedForm().LHS; }
281+
const Expr *getRHS() const { return getDecomposedForm().RHS; }
282+
283+
SourceLocation getOperatorLoc() const LLVM_READONLY {
284+
return getDecomposedForm().InnerBinOp->getExprLoc();
285+
}
286+
SourceLocation getExprLoc() const LLVM_READONLY { return getOperatorLoc(); }
287+
288+
/// Compute the begin and end locations from the decomposed form.
289+
/// The locations of the semantic form are not reliable if this is
290+
/// a reversed expression.
291+
//@{
292+
SourceLocation getBeginLoc() const LLVM_READONLY {
293+
return getDecomposedForm().LHS->getBeginLoc();
294+
}
295+
SourceLocation getEndLoc() const LLVM_READONLY {
296+
return getDecomposedForm().RHS->getEndLoc();
297+
}
298+
SourceRange getSourceRange() const LLVM_READONLY {
299+
DecomposedForm DF = getDecomposedForm();
300+
return SourceRange(DF.LHS->getBeginLoc(), DF.RHS->getEndLoc());
301+
}
302+
//@}
303+
304+
child_range children() {
305+
return child_range(&SemanticForm, &SemanticForm + 1);
306+
}
307+
308+
static bool classof(const Stmt *T) {
309+
return T->getStmtClass() == CXXRewrittenBinaryOperatorClass;
310+
}
311+
};
312+
223313
/// Represents a call to a CUDA kernel function.
224314
class CUDAKernelCallExpr final : public CallExpr {
225315
friend class ASTStmtReader;

include/clang/AST/RecursiveASTVisitor.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2606,6 +2606,15 @@ DEF_TRAVERSE_STMT(SEHLeaveStmt, {})
26062606
DEF_TRAVERSE_STMT(CapturedStmt, { TRY_TO(TraverseDecl(S->getCapturedDecl())); })
26072607

26082608
DEF_TRAVERSE_STMT(CXXOperatorCallExpr, {})
2609+
DEF_TRAVERSE_STMT(CXXRewrittenBinaryOperator, {
2610+
if (!getDerived().shouldVisitImplicitCode()) {
2611+
CXXRewrittenBinaryOperator::DecomposedForm Decomposed =
2612+
S->getDecomposedForm();
2613+
TRY_TO(TraverseStmt(const_cast<Expr*>(Decomposed.LHS)));
2614+
TRY_TO(TraverseStmt(const_cast<Expr*>(Decomposed.RHS)));
2615+
ShouldVisitChildren = false;
2616+
}
2617+
})
26092618
DEF_TRAVERSE_STMT(OpaqueValueExpr, {})
26102619
DEF_TRAVERSE_STMT(TypoExpr, {})
26112620
DEF_TRAVERSE_STMT(CUDAKernelCallExpr, {})

include/clang/AST/Stmt.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,15 @@ class alignas(void *) Stmt {
604604
unsigned FPFeatures : 3;
605605
};
606606

607+
class CXXRewrittenBinaryOperatorBitfields {
608+
friend class ASTStmtReader;
609+
friend class CXXRewrittenBinaryOperator;
610+
611+
unsigned : NumCallExprBits;
612+
613+
unsigned IsReversed : 1;
614+
};
615+
607616
class CXXBoolLiteralExprBitfields {
608617
friend class CXXBoolLiteralExpr;
609618

@@ -978,6 +987,7 @@ class alignas(void *) Stmt {
978987

979988
// C++ Expressions
980989
CXXOperatorCallExprBitfields CXXOperatorCallExprBits;
990+
CXXRewrittenBinaryOperatorBitfields CXXRewrittenBinaryOperatorBits;
981991
CXXBoolLiteralExprBitfields CXXBoolLiteralExprBits;
982992
CXXNullPtrLiteralExprBitfields CXXNullPtrLiteralExprBits;
983993
CXXThisExprBitfields CXXThisExprBits;

include/clang/Basic/StmtNodes.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ def GNUNullExpr : DStmt<Expr>;
114114
// C++ Expressions.
115115
def CXXOperatorCallExpr : DStmt<CallExpr>;
116116
def CXXMemberCallExpr : DStmt<CallExpr>;
117+
def CXXRewrittenBinaryOperator : DStmt<Expr>;
117118
def CXXNamedCastExpr : DStmt<ExplicitCastExpr, 1>;
118119
def CXXStaticCastExpr : DStmt<CXXNamedCastExpr>;
119120
def CXXDynamicCastExpr : DStmt<CXXNamedCastExpr>;

include/clang/Serialization/ASTBitCodes.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1845,6 +1845,9 @@ namespace serialization {
18451845
/// A CXXMemberCallExpr record.
18461846
EXPR_CXX_MEMBER_CALL,
18471847

1848+
/// A CXXRewrittenBinaryOperator record.
1849+
EXPR_CXX_REWRITTEN_BINARY_OPERATOR,
1850+
18481851
/// A CXXConstructExpr record.
18491852
EXPR_CXX_CONSTRUCT,
18501853

lib/AST/Expr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3473,6 +3473,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
34733473
case ArrayInitLoopExprClass:
34743474
case ParenListExprClass:
34753475
case CXXPseudoDestructorExprClass:
3476+
case CXXRewrittenBinaryOperatorClass:
34763477
case CXXStdInitializerListExprClass:
34773478
case SubstNonTypeTemplateParmExprClass:
34783479
case MaterializeTemporaryExprClass:

lib/AST/ExprCXX.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,76 @@ bool CXXOperatorCallExpr::isInfixBinaryOp() const {
5858
}
5959
}
6060

61+
CXXRewrittenBinaryOperator::DecomposedForm
62+
CXXRewrittenBinaryOperator::getDecomposedForm() const {
63+
DecomposedForm Result = {};
64+
const Expr *E = getSemanticForm()->IgnoreImplicit();
65+
66+
// Remove an outer '!' if it exists (only happens for a '!=' rewrite).
67+
bool SkippedNot = false;
68+
if (auto *NotEq = dyn_cast<UnaryOperator>(E)) {
69+
assert(NotEq->getOpcode() == UO_LNot);
70+
E = NotEq->getSubExpr()->IgnoreImplicit();
71+
SkippedNot = true;
72+
}
73+
74+
// Decompose the outer binary operator.
75+
if (auto *BO = dyn_cast<BinaryOperator>(E)) {
76+
assert(!SkippedNot || BO->getOpcode() == BO_EQ);
77+
Result.Opcode = SkippedNot ? BO_NE : BO->getOpcode();
78+
Result.LHS = BO->getLHS();
79+
Result.RHS = BO->getRHS();
80+
Result.InnerBinOp = BO;
81+
} else if (auto *BO = dyn_cast<CXXOperatorCallExpr>(E)) {
82+
assert(!SkippedNot || BO->getOperator() == OO_Equal);
83+
assert(BO->isInfixBinaryOp());
84+
switch (BO->getOperator()) {
85+
case OO_Less: Result.Opcode = BO_LT; break;
86+
case OO_LessEqual: Result.Opcode = BO_LE; break;
87+
case OO_Greater: Result.Opcode = BO_GT; break;
88+
case OO_GreaterEqual: Result.Opcode = BO_GE; break;
89+
case OO_Spaceship: Result.Opcode = BO_Cmp; break;
90+
case OO_EqualEqual: Result.Opcode = SkippedNot ? BO_NE : BO_EQ; break;
91+
default: llvm_unreachable("unexpected binop in rewritten operator expr");
92+
}
93+
Result.LHS = BO->getArg(0);
94+
Result.RHS = BO->getArg(1);
95+
Result.InnerBinOp = BO;
96+
} else {
97+
llvm_unreachable("unexpected rewritten operator form");
98+
}
99+
100+
// Put the operands in the right order for == and !=, and canonicalize the
101+
// <=> subexpression onto the LHS for all other forms.
102+
if (isReversed())
103+
std::swap(Result.LHS, Result.RHS);
104+
105+
// If this isn't a spaceship rewrite, we're done.
106+
if (Result.Opcode == BO_EQ || Result.Opcode == BO_NE)
107+
return Result;
108+
109+
// Otherwise, we expect a <=> to now be on the LHS.
110+
E = Result.InnerBinOp->IgnoreImplicit();
111+
if (auto *BO = dyn_cast<BinaryOperator>(E)) {
112+
assert(BO->getOpcode() == BO_Cmp);
113+
Result.LHS = BO->getLHS();
114+
Result.RHS = BO->getRHS();
115+
Result.InnerBinOp = BO;
116+
} else if (auto *BO = dyn_cast<CXXOperatorCallExpr>(E)) {
117+
assert(BO->getOperator() == OO_Spaceship);
118+
Result.LHS = BO->getArg(0);
119+
Result.RHS = BO->getArg(1);
120+
Result.InnerBinOp = BO;
121+
} else {
122+
llvm_unreachable("unexpected rewritten operator form");
123+
}
124+
125+
// Put the comparison operands in the right order.
126+
if (isReversed())
127+
std::swap(Result.LHS, Result.RHS);
128+
return Result;
129+
}
130+
61131
bool CXXTypeidExpr::isPotentiallyEvaluated() const {
62132
if (isTypeOperand())
63133
return false;

lib/AST/ExprClassification.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,10 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
307307
case Expr::CUDAKernelCallExprClass:
308308
return ClassifyUnnamed(Ctx, cast<CallExpr>(E)->getCallReturnType(Ctx));
309309

310+
case Expr::CXXRewrittenBinaryOperatorClass:
311+
return ClassifyInternal(
312+
Ctx, cast<CXXRewrittenBinaryOperator>(E)->getSemanticForm());
313+
310314
// __builtin_choose_expr is equivalent to the chosen expression.
311315
case Expr::ChooseExprClass:
312316
return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr());

lib/AST/ExprConstant.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6765,6 +6765,10 @@ class ExprEvaluatorBase
67656765
}
67666766
}
67676767

6768+
bool VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *E) {
6769+
return StmtVisitorTy::Visit(E->getSemanticForm());
6770+
}
6771+
67686772
bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) {
67696773
// Evaluate and cache the common expression. We treat it as a temporary,
67706774
// even though it's not quite the same thing.
@@ -13945,6 +13949,9 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
1394513949
return CheckEvalInICE(E, Ctx);
1394613950
return ICEDiag(IK_NotICE, E->getBeginLoc());
1394713951
}
13952+
case Expr::CXXRewrittenBinaryOperatorClass:
13953+
return CheckICE(cast<CXXRewrittenBinaryOperator>(E)->getSemanticForm(),
13954+
Ctx);
1394813955
case Expr::DeclRefExprClass: {
1394913956
if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
1395013957
return NoDiag();

lib/AST/ItaniumMangle.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4090,6 +4090,17 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
40904090
break;
40914091
}
40924092

4093+
case Expr::CXXRewrittenBinaryOperatorClass: {
4094+
// The mangled form represents the original syntax.
4095+
CXXRewrittenBinaryOperator::DecomposedForm Decomposed =
4096+
cast<CXXRewrittenBinaryOperator>(E)->getDecomposedForm();
4097+
mangleOperatorName(BinaryOperator::getOverloadedOperator(Decomposed.Opcode),
4098+
/*Arity=*/2);
4099+
mangleExpression(Decomposed.LHS);
4100+
mangleExpression(Decomposed.RHS);
4101+
break;
4102+
}
4103+
40934104
case Expr::ConditionalOperatorClass: {
40944105
const ConditionalOperator *CO = cast<ConditionalOperator>(E);
40954106
mangleOperatorName(OO_Conditional, /*Arity=*/3);

0 commit comments

Comments
 (0)