diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/Expr.cpp | 1 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 70 | ||||
-rw-r--r-- | lib/AST/ExprClassification.cpp | 4 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 7 | ||||
-rw-r--r-- | lib/AST/ItaniumMangle.cpp | 11 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 9 | ||||
-rw-r--r-- | lib/AST/StmtProfile.cpp | 10 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGExprAgg.cpp | 3 | ||||
-rw-r--r-- | lib/CodeGen/CGExprComplex.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGExprScalar.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaExceptionSpec.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 34 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderStmt.cpp | 11 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 1 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterStmt.cpp | 8 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 |
17 files changed, 181 insertions, 0 deletions
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index f2e625124c..3438c3aadc 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -3473,6 +3473,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case ArrayInitLoopExprClass: case ParenListExprClass: case CXXPseudoDestructorExprClass: + case CXXRewrittenBinaryOperatorClass: case CXXStdInitializerListExprClass: case SubstNonTypeTemplateParmExprClass: case MaterializeTemporaryExprClass: diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index a9b7c00a8b..0b0d3c6880 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -58,6 +58,76 @@ bool CXXOperatorCallExpr::isInfixBinaryOp() const { } } +CXXRewrittenBinaryOperator::DecomposedForm +CXXRewrittenBinaryOperator::getDecomposedForm() const { + DecomposedForm Result = {}; + const Expr *E = getSemanticForm()->IgnoreImplicit(); + + // Remove an outer '!' if it exists (only happens for a '!=' rewrite). + bool SkippedNot = false; + if (auto *NotEq = dyn_cast<UnaryOperator>(E)) { + assert(NotEq->getOpcode() == UO_LNot); + E = NotEq->getSubExpr()->IgnoreImplicit(); + SkippedNot = true; + } + + // Decompose the outer binary operator. + if (auto *BO = dyn_cast<BinaryOperator>(E)) { + assert(!SkippedNot || BO->getOpcode() == BO_EQ); + Result.Opcode = SkippedNot ? BO_NE : BO->getOpcode(); + Result.LHS = BO->getLHS(); + Result.RHS = BO->getRHS(); + Result.InnerBinOp = BO; + } else if (auto *BO = dyn_cast<CXXOperatorCallExpr>(E)) { + assert(!SkippedNot || BO->getOperator() == OO_Equal); + assert(BO->isInfixBinaryOp()); + switch (BO->getOperator()) { + case OO_Less: Result.Opcode = BO_LT; break; + case OO_LessEqual: Result.Opcode = BO_LE; break; + case OO_Greater: Result.Opcode = BO_GT; break; + case OO_GreaterEqual: Result.Opcode = BO_GE; break; + case OO_Spaceship: Result.Opcode = BO_Cmp; break; + case OO_EqualEqual: Result.Opcode = SkippedNot ? BO_NE : BO_EQ; break; + default: llvm_unreachable("unexpected binop in rewritten operator expr"); + } + Result.LHS = BO->getArg(0); + Result.RHS = BO->getArg(1); + Result.InnerBinOp = BO; + } else { + llvm_unreachable("unexpected rewritten operator form"); + } + + // Put the operands in the right order for == and !=, and canonicalize the + // <=> subexpression onto the LHS for all other forms. + if (isReversed()) + std::swap(Result.LHS, Result.RHS); + + // If this isn't a spaceship rewrite, we're done. + if (Result.Opcode == BO_EQ || Result.Opcode == BO_NE) + return Result; + + // Otherwise, we expect a <=> to now be on the LHS. + E = Result.InnerBinOp->IgnoreImplicit(); + if (auto *BO = dyn_cast<BinaryOperator>(E)) { + assert(BO->getOpcode() == BO_Cmp); + Result.LHS = BO->getLHS(); + Result.RHS = BO->getRHS(); + Result.InnerBinOp = BO; + } else if (auto *BO = dyn_cast<CXXOperatorCallExpr>(E)) { + assert(BO->getOperator() == OO_Spaceship); + Result.LHS = BO->getArg(0); + Result.RHS = BO->getArg(1); + Result.InnerBinOp = BO; + } else { + llvm_unreachable("unexpected rewritten operator form"); + } + + // Put the comparison operands in the right order. + if (isReversed()) + std::swap(Result.LHS, Result.RHS); + return Result; +} + bool CXXTypeidExpr::isPotentiallyEvaluated() const { if (isTypeOperand()) return false; diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index d109cd3d03..9dbf6fe9e0 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -307,6 +307,10 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CUDAKernelCallExprClass: return ClassifyUnnamed(Ctx, cast<CallExpr>(E)->getCallReturnType(Ctx)); + case Expr::CXXRewrittenBinaryOperatorClass: + return ClassifyInternal( + Ctx, cast<CXXRewrittenBinaryOperator>(E)->getSemanticForm()); + // __builtin_choose_expr is equivalent to the chosen expression. case Expr::ChooseExprClass: return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr()); diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index a379a335b2..42c746e602 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -6765,6 +6765,10 @@ public: } } + bool VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *E) { + return StmtVisitorTy::Visit(E->getSemanticForm()); + } + bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) { // Evaluate and cache the common expression. We treat it as a temporary, // even though it's not quite the same thing. @@ -13945,6 +13949,9 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { return CheckEvalInICE(E, Ctx); return ICEDiag(IK_NotICE, E->getBeginLoc()); } + case Expr::CXXRewrittenBinaryOperatorClass: + return CheckICE(cast<CXXRewrittenBinaryOperator>(E)->getSemanticForm(), + Ctx); case Expr::DeclRefExprClass: { if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl())) return NoDiag(); diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 534a92d2cb..c55a901375 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -4090,6 +4090,17 @@ recurse: break; } + case Expr::CXXRewrittenBinaryOperatorClass: { + // The mangled form represents the original syntax. + CXXRewrittenBinaryOperator::DecomposedForm Decomposed = + cast<CXXRewrittenBinaryOperator>(E)->getDecomposedForm(); + mangleOperatorName(BinaryOperator::getOverloadedOperator(Decomposed.Opcode), + /*Arity=*/2); + mangleExpression(Decomposed.LHS); + mangleExpression(Decomposed.RHS); + break; + } + case Expr::ConditionalOperatorClass: { const ConditionalOperator *CO = cast<ConditionalOperator>(E); mangleOperatorName(OO_Conditional, /*Arity=*/3); diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 5b92ca0ac9..7759ff6c13 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1697,6 +1697,15 @@ void StmtPrinter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *Node) { OS << ")"; } +void StmtPrinter::VisitCXXRewrittenBinaryOperator( + CXXRewrittenBinaryOperator *Node) { + CXXRewrittenBinaryOperator::DecomposedForm Decomposed = + Node->getDecomposedForm(); + PrintExpr(const_cast<Expr*>(Decomposed.LHS)); + OS << ' ' << BinaryOperator::getOpcodeStr(Decomposed.Opcode) << ' '; + PrintExpr(const_cast<Expr*>(Decomposed.RHS)); +} + void StmtPrinter::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { OS << Node->getCastName() << '<'; Node->getTypeAsWritten().print(OS, Policy); diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 0c4916e6ab..d1e8565389 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -1557,6 +1557,16 @@ void StmtProfiler::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) { ID.AddInteger(S->getOperator()); } +void StmtProfiler::VisitCXXRewrittenBinaryOperator( + const CXXRewrittenBinaryOperator *S) { + // If a rewritten operator were ever to be type-dependent, we should profile + // it following its syntactic operator. + assert(!S->isTypeDependent() && + "resolved rewritten operator should never be type-dependent"); + ID.AddBoolean(S->isReversed()); + VisitExpr(S->getSemanticForm()); +} + #if defined(_MSC_VER) && !defined(__clang__) #if _MSC_VER == 1911 #pragma optimize("", on) diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 2bd1b0ba7e..dcd365c8ea 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -1267,6 +1267,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { case Expr::CXXOperatorCallExprClass: case Expr::UserDefinedLiteralClass: return EmitCallExprLValue(cast<CallExpr>(E)); + case Expr::CXXRewrittenBinaryOperatorClass: + return EmitLValue(cast<CXXRewrittenBinaryOperator>(E)->getSemanticForm()); case Expr::VAArgExprClass: return EmitVAArgExprLValue(cast<VAArgExpr>(E)); case Expr::DeclRefExprClass: diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index ab51512ef9..2f0e493761 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -150,6 +150,9 @@ public: void VisitBinAssign(const BinaryOperator *E); void VisitBinComma(const BinaryOperator *E); void VisitBinCmp(const BinaryOperator *E); + void VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *E) { + Visit(E->getSemanticForm()); + } void VisitObjCMessageExpr(ObjCMessageExpr *E); void VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 6a5fb45ba2..385f87f12a 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -279,6 +279,10 @@ public: return EmitBinDiv(EmitBinOps(E)); } + ComplexPairTy VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *E) { + return Visit(E->getSemanticForm()); + } + // Compound assignments. ComplexPairTy VisitBinAddAssign(const CompoundAssignOperator *E) { return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinAdd); diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index f1396137d7..55a413a2a7 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -817,6 +817,10 @@ public: Value *VisitBinPtrMemD(const Expr *E) { return EmitLoadOfLValue(E); } Value *VisitBinPtrMemI(const Expr *E) { return EmitLoadOfLValue(E); } + Value *VisitCXXRewrittenBinaryOperator(CXXRewrittenBinaryOperator *E) { + return Visit(E->getSemanticForm()); + } + // Other Operators. Value *VisitBlockExpr(const BlockExpr *BE); Value *VisitAbstractConditionalOperator(const AbstractConditionalOperator *); diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 76fd10d2e6..b334ba568a 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -1201,6 +1201,7 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::CoyieldExprClass: case Expr::CXXConstCastExprClass: case Expr::CXXReinterpretCastExprClass: + case Expr::CXXRewrittenBinaryOperatorClass: case Expr::BuiltinBitCastExprClass: case Expr::CXXStdInitializerListExprClass: case Expr::DesignatedInitExprClass: diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index f8549471c5..461cd909c2 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -2353,6 +2353,17 @@ public: return getSema().BuildBinOp(/*Scope=*/nullptr, OpLoc, Opc, LHS, RHS); } + /// Build a new rewritten operator expression. + /// + /// By default, builds the rewritten operator without performing any semantic + /// analysis. Subclasses may override this routine to provide different + /// behavior. + ExprResult RebuildCXXRewrittenBinaryOperator(Expr *SemanticForm, + bool IsReversed) { + return new (getSema().Context) + CXXRewrittenBinaryOperator(SemanticForm, IsReversed); + } + /// Build a new conditional operator expression. /// /// By default, performs semantic analysis to build the new expression. @@ -9769,6 +9780,29 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) { LHS.get(), RHS.get()); } +template <typename Derived> +ExprResult TreeTransform<Derived>::TransformCXXRewrittenBinaryOperator( + CXXRewrittenBinaryOperator *E) { + // FIXME: C++ [temp.deduct]p7 "The substitution proceeds in lexical order and + // stops when a condition that causes deduction to fail is encountered." + // requires us to substitute into the LHS before the RHS, even in a rewrite + // that reversed the operand order. + // + // We can't decompose back to a binary operator here, because that would lose + // the unqualified lookup results from the phase 1 name lookup. + + ExprResult SemanticForm = getDerived().TransformExpr(E->getSemanticForm()); + if (SemanticForm.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + SemanticForm.get() == E->getSemanticForm()) + return E; + + return getDerived().RebuildCXXRewrittenBinaryOperator(SemanticForm.get(), + E->isReversed()); +} + template<typename Derived> ExprResult TreeTransform<Derived>::TransformCompoundAssignOperator( diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 509e206c81..a275e0c305 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -1440,6 +1440,13 @@ void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { E->Range = Record.readSourceRange(); } +void ASTStmtReader::VisitCXXRewrittenBinaryOperator( + CXXRewrittenBinaryOperator *E) { + VisitExpr(E); + E->CXXRewrittenBinaryOperatorBits.IsReversed = Record.readInt(); + E->SemanticForm = Record.readSubExpr(); +} + void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { VisitExpr(E); @@ -3252,6 +3259,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields], Empty); break; + case EXPR_CXX_REWRITTEN_BINARY_OPERATOR: + S = new (Context) CXXRewrittenBinaryOperator(Empty); + break; + case EXPR_CXX_CONSTRUCT: S = CXXConstructExpr::CreateEmpty( Context, diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 6f3b367aed..c6b05c9a17 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -1024,6 +1024,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream, RECORD(STMT_CXX_FOR_RANGE); RECORD(EXPR_CXX_OPERATOR_CALL); RECORD(EXPR_CXX_MEMBER_CALL); + RECORD(EXPR_CXX_REWRITTEN_BINARY_OPERATOR); RECORD(EXPR_CXX_CONSTRUCT); RECORD(EXPR_CXX_TEMPORARY_OBJECT); RECORD(EXPR_CXX_STATIC_CAST); diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 84a532496d..c39d4d39bc 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -1375,6 +1375,14 @@ void ASTStmtWriter::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { Code = serialization::EXPR_CXX_MEMBER_CALL; } +void ASTStmtWriter::VisitCXXRewrittenBinaryOperator( + CXXRewrittenBinaryOperator *E) { + VisitExpr(E); + Record.push_back(E->isReversed()); + Record.AddStmt(E->getSemanticForm()); + Code = serialization::EXPR_CXX_REWRITTEN_BINARY_OPERATOR; +} + void ASTStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) { VisitExpr(E); diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index a148088c2b..e92e95354f 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1372,6 +1372,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::OpaqueValueExprClass: case Stmt::AsTypeExprClass: case Stmt::ConceptSpecializationExprClass: + case Stmt::CXXRewrittenBinaryOperatorClass: // Fall through. // Cases we intentionally don't evaluate, since they don't need |