diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -1779,6 +1779,55 @@ } }; +class CXXStandardLibraryCastExpr final + : public CastExpr, + private llvm::TrailingObjects { + friend class ASTStmtReader; + + CXXStandardLibraryCastExpr(QualType exprTy, ExprValueKind VK, CastKind kind, + Expr *op, Expr *OriginalExpression, + unsigned PathSize, const CXXCastPath *BasePath, + FPOptionsOverride FPO) + : CastExpr(CXXStandardLibraryCastExprClass, exprTy, VK, kind, op, + PathSize, FPO.requiresTrailingStorage()), + OriginalExpression(OriginalExpression) {} + + explicit CXXStandardLibraryCastExpr(EmptyShell Shell, unsigned PathSize, + bool HasFPFeatures) + : CastExpr(CXXStandardLibraryCastExprClass, Shell, PathSize, + HasFPFeatures) {} + + unsigned numTrailingObjects(OverloadToken) const { + return path_size(); + } + + Expr *OriginalExpression; + +public: + friend TrailingObjects; + friend class CastExpr; + + static CXXStandardLibraryCastExpr * + Create(const ASTContext &Context, QualType T, ExprValueKind VK, CastKind Kind, + Expr *Op, Expr *OriginalExpression, const CXXCastPath *BasePath, + FPOptionsOverride FPO); + + static CXXStandardLibraryCastExpr * + CreateEmpty(const ASTContext &Context, unsigned PathSize, bool HasFPFeatures); + + /* Expr* getOriginalExpression() const { + return OriginalExpression; + }*/ + + SourceLocation getBeginLoc() const LLVM_READONLY; + SourceLocation getEndLoc() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXStandardLibraryCastExprClass; + } +}; + /// Represents a C++ functional cast expression that builds a /// temporary object. /// diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2312,6 +2312,8 @@ // source code. }) +DEF_TRAVERSE_STMT(CXXStandardLibraryCastExpr, {}) + DEF_TRAVERSE_STMT(CStyleCastExpr, { TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); }) diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -271,6 +271,7 @@ void VisitCXXThisExpr(const CXXThisExpr *Node); void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node); void VisitCXXStaticCastExpr(const CXXStaticCastExpr *Node); + void VisitCXXStandardLibraryCast(const CXXStandardLibraryCastExpr *Node); void VisitCXXUnresolvedConstructExpr(const CXXUnresolvedConstructExpr *Node); void VisitCXXConstructExpr(const CXXConstructExpr *Node); void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node); diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -2574,6 +2574,10 @@ extern const internal::VariadicDynCastAllOfMatcher cStyleCastExpr; +extern const internal::VariadicDynCastAllOfMatcher + cxxStandardLibraryCastExpr; + /// Matches explicit cast expressions. /// /// Matches any cast expression written in user code, whether it be a diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -123,6 +123,7 @@ def CXXConstCastExpr : StmtNode; def CXXAddrspaceCastExpr : StmtNode; def CXXFunctionalCastExpr : StmtNode; +def CXXStandardLibraryCastExpr : StmtNode; def CXXTypeidExpr : StmtNode; def UserDefinedLiteral : StmtNode; def CXXBoolLiteralExpr : StmtNode; diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1800,6 +1800,9 @@ /// A CXXStaticCastExpr record. EXPR_CXX_STATIC_CAST, + /// A CXXStandardLibraryCastExpr record. + EXPR_CXX_STL_CAST, + /// A CXXDynamicCastExpr record. EXPR_CXX_DYNAMIC_CAST, diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3432,6 +3432,7 @@ case CXXStaticCastExprClass: case CXXReinterpretCastExprClass: case CXXConstCastExprClass: + case CXXStandardLibraryCastExprClass: case CXXAddrspaceCastExprClass: case CXXFunctionalCastExprClass: case BuiltinBitCastExprClass: { diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -871,6 +871,40 @@ return RParenLoc.isValid() ? RParenLoc : getSubExpr()->getEndLoc(); } +CXXStandardLibraryCastExpr *CXXStandardLibraryCastExpr::Create( + const ASTContext &C, QualType T, ExprValueKind VK, CastKind Kind, Expr *Op, + Expr *OriginalExpression, const CXXCastPath *BasePath, + FPOptionsOverride FPO) { + unsigned PathSize = (BasePath ? BasePath->size() : 0); + void *Buffer = + C.Allocate(totalSizeToAlloc( + PathSize, FPO.requiresTrailingStorage())); + auto *E = new (Buffer) CXXStandardLibraryCastExpr( + T, VK, Kind, Op, OriginalExpression, PathSize, BasePath, FPO); + if (PathSize) + std::uninitialized_copy_n(BasePath->data(), BasePath->size(), + E->getTrailingObjects()); + return E; +} + +CXXStandardLibraryCastExpr * +CXXStandardLibraryCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize, + bool HasFPFeatures) { + void *Buffer = + C.Allocate(totalSizeToAlloc( + PathSize, HasFPFeatures)); + return new (Buffer) + CXXStandardLibraryCastExpr(EmptyShell(), PathSize, HasFPFeatures); +} + +SourceLocation CXXStandardLibraryCastExpr::getBeginLoc() const { + return OriginalExpression->getBeginLoc(); +} + +SourceLocation CXXStandardLibraryCastExpr::getEndLoc() const { + return OriginalExpression->getEndLoc(); +} + UserDefinedLiteral::UserDefinedLiteral(Expr *Fn, ArrayRef Args, QualType Ty, ExprValueKind VK, SourceLocation LitEndLoc, diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -363,6 +363,9 @@ if (!Lang.CPlusPlus) return Cl::CL_PRValue; return ClassifyUnnamed(Ctx, cast(E)->getTypeAsWritten()); + case Expr::CXXStandardLibraryCastExprClass: + return ClassifyExprValueKind(Lang, E, E->getValueKind()); + case Expr::CXXUnresolvedConstructExprClass: return ClassifyUnnamed(Ctx, cast(E)->getTypeAsWritten()); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -15362,6 +15362,7 @@ case Expr::CXXFunctionalCastExprClass: case Expr::CXXStaticCastExprClass: case Expr::CXXReinterpretCastExprClass: + case Expr::CXXStandardLibraryCastExprClass: case Expr::CXXConstCastExprClass: case Expr::ObjCBridgedCastExprClass: { const Expr *SubExpr = cast(E)->getSubExpr(); diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4661,6 +4661,7 @@ break; } + case Expr::CXXStandardLibraryCastExprClass: case Expr::CXXStaticCastExprClass: NotPrimaryExpr(); mangleCastExpression(E, "sc"); diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1495,6 +1495,12 @@ PrintExpr(Node->getSubExpr()); } +void StmtPrinter::VisitCXXStandardLibraryCastExpr( + CXXStandardLibraryCastExpr *Node) { + // No need to print anything, simply forward to the subexpression. + PrintExpr(Node->getSubExpr()); +} + void StmtPrinter::VisitBinaryOperator(BinaryOperator *Node) { PrintExpr(Node->getLHS()); OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " "; diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -1305,6 +1305,11 @@ ID.AddInteger(S->getValueKind()); } +void StmtProfiler::VisitCXXStandardLibraryCastExpr( + const CXXStandardLibraryCastExpr *S) { + VisitCastExpr(S); +} + void StmtProfiler::VisitExplicitCastExpr(const ExplicitCastExpr *S) { VisitCastExpr(S); VisitType(S->getTypeAsWritten()); diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1146,6 +1146,17 @@ printFPOptions(Node->getFPFeatures()); } +void TextNodeDumper::VisitCXXStandardLibraryCast( + const CXXStandardLibraryCastExpr *Node) { + VisitCastExpr(Node); + OS << "<" << Node->getType().getAsString() << ">" + << "<" << Node->getCastKindName(); + dumpBasePath(OS, Node); + OS << ">"; + + // Visit(Node->getOriginalExpression()); +} + void TextNodeDumper::VisitCXXUnresolvedConstructExpr( const CXXUnresolvedConstructExpr *Node) { dumpType(Node->getTypeAsWritten()); diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -956,6 +956,8 @@ explicitCastExpr; const internal::VariadicDynCastAllOfMatcher implicitCastExpr; +const internal::VariadicDynCastAllOfMatcher + cssStandardLibraryCastExpr; const internal::VariadicDynCastAllOfMatcher castExpr; const internal::VariadicDynCastAllOfMatcher cxxFunctionalCastExpr; diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -201,6 +201,7 @@ REGISTER_MATCHER(cxxReinterpretCastExpr); REGISTER_MATCHER(cxxRewrittenBinaryOperator); REGISTER_MATCHER(cxxStaticCastExpr); + REGISTER_MATCHER(cxxStandardLibraryCastExpr); REGISTER_MATCHER(cxxStdInitializerListExpr); REGISTER_MATCHER(cxxTemporaryObjectExpr); REGISTER_MATCHER(cxxThisExpr); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1413,6 +1413,7 @@ case Expr::CStyleCastExprClass: case Expr::CXXFunctionalCastExprClass: case Expr::CXXStaticCastExprClass: + case Expr::CXXStandardLibraryCastExprClass: case Expr::CXXDynamicCastExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::CXXConstCastExprClass: diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1305,6 +1305,7 @@ case Expr::CompoundAssignOperatorClass: case Expr::CStyleCastExprClass: case Expr::CXXStaticCastExprClass: + case Expr::CXXStandardLibraryCastExprClass: case Expr::CXXFunctionalCastExprClass: case Expr::ImplicitCastExprClass: case Expr::MaterializeTemporaryExprClass: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6443,6 +6443,60 @@ } } + auto RewriteQualifiedCallsToStandardCastFunction = + [&](Expr *Fn) -> ExprResult { + auto *ULE = dyn_cast_or_null(Fn->IgnoreParens()); + if (ArgExprs.size() != 1 || Expr::hasAnyTypeDependentArguments(ArgExprs) || + !ULE || !ULE->getQualifier() || + !ULE->getQualifier()->getAsNamespace()->isStdNamespace()) + return {}; + + ULE->dumpColor(); + llvm::outs() << "Template Args: " << ULE->getNumTemplateArgs() << "\n"; + + IdentifierInfo *ID = ULE->getName().isIdentifier() + ? ULE->getName().getAsIdentifierInfo() + : nullptr; + if (!ID) + return {}; + + Expr *Arg = ArgExprs.front(); + + if (ULE->getNumTemplateArgs() == 0 && ID->isStr("move")) { + llvm::outs() + << "Replacing a call to std::move before overload resolution\n"; + return CXXStandardLibraryCastExpr::Create( + Context, Arg->getType().getNonReferenceType(), VK_XValue, CK_NoOp, + Arg, Fn, nullptr, {}); + } + + if (ULE->getNumTemplateArgs() == 1 && ID->isStr("forward")) { + auto TemplateArg = ULE->getTemplateArgs()->getArgument(); + if (TemplateArg.isDependent() || + TemplateArg.getKind() != TemplateArgument::ArgKind::Type) + return {}; + + const auto TemplateType = TemplateArg.getAsType().getNonReferenceType(); + const auto ExpressionType = Arg->getType().getNonReferenceType(); + + if (!Context.hasSameType(TemplateType, ExpressionType)) + return {}; + + llvm::outs() + << "Replacing a call to std::forward before overload resolution\n"; + return CXXStandardLibraryCastExpr::Create(Context, TemplateType, + Arg->getValueKind(), CK_NoOp, + Arg, Fn, nullptr, {}); + } + + return {}; + }; + + ExprResult E = RewriteQualifiedCallsToStandardCastFunction(Fn); + if (E.isUsable()) { + return E; + } + // Check for overloaded calls. This can happen even in C due to extensions. if (Fn->getType() == Context.OverloadTy) { OverloadExpr::FindResult find = OverloadExpr::find(Fn); @@ -6846,7 +6900,29 @@ return ExprError(); } - return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall), FDecl); + auto TransformStdMoveAndForwardIntoCast = [&](CallExpr *Call) -> Expr * { + const bool isStd = NDecl && NDecl->isInStdNamespace(); + if (!getLangOpts().CPlusPlus || !isStd || !NDecl) + return Call; + + if (Call->getNumArgs() != 1 && !(NDecl->getName().compare("move") == 0 || + NDecl->getName().compare("forward") == 0)) + return Call; + + Expr *A = TheCall->getArg(0); + if (A->getType().getCanonicalType().getNonReferenceType() != + TheCall->getType().getCanonicalType().getNonReferenceType()) + return Call; + + if (A->isRValue() && Context.hasSameType(A->getType(), TheCall->getType())) + return A; + + return CXXStandardLibraryCastExpr::Create( + Context, TheCall->getType(), TheCall->getValueKind(), CastKind::CK_NoOp, + A, TheCall, nullptr, {}); + }; + return CheckForImmediateInvocation( + MaybeBindToTemporary(TransformStdMoveAndForwardIntoCast(TheCall)), FDecl); } ExprResult diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -10899,6 +10899,14 @@ return getDerived().TransformExpr(E->getSubExprAsWritten()); } +template +ExprResult TreeTransform::TransformCXXStandardLibraryCastExpr( + CXXStandardLibraryCastExpr *E) { + // CXXStandardLibraryCastExpr casts are eliminated during transformation, + // since they will be recomputed by semantic analysis after transformation. + return E; +} + template ExprResult TreeTransform::TransformCStyleCastExpr(CStyleCastExpr *E) { diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1143,6 +1143,12 @@ E->setIsPartOfExplicitCast(Record.readInt()); } +void ASTStmtReader::VisitCXXStandardLibraryCastExpr( + CXXStandardLibraryCastExpr *E) { + VisitCastExpr(E); + E->OriginalExpression = Record.readSubExpr(); +} + void ASTStmtReader::VisitExplicitCastExpr(ExplicitCastExpr *E) { VisitCastExpr(E); E->setTypeInfoAsWritten(readTypeSourceInfo()); @@ -2930,6 +2936,13 @@ /*HasFPFeatures*/ Record[ASTStmtReader::NumExprFields + 1]); break; + case EXPR_CXX_STL_CAST: + S = CXXStandardLibraryCastExpr::CreateEmpty( + Context, + /*PathSize*/ Record[ASTStmtReader::NumExprFields], + /*HasFPFeatures*/ Record[ASTStmtReader::NumExprFields + 1]); + break; + case EXPR_CSTYLE_CAST: S = CStyleCastExpr::CreateEmpty( Context, diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1652,6 +1652,13 @@ Code = serialization::EXPR_CXX_STATIC_CAST; } +void ASTStmtWriter::VisitCXXStandardLibraryCastExpr( + CXXStandardLibraryCastExpr *E) { + VisitCastExpr(E); + VisitExpr(E); + Code = serialization::EXPR_CXX_STATIC_CAST; +} + void ASTStmtWriter::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) { VisitCXXNamedCastExpr(E); Code = serialization::EXPR_CXX_DYNAMIC_CAST; diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1720,6 +1720,7 @@ case Stmt::ImplicitCastExprClass: case Stmt::CStyleCastExprClass: case Stmt::CXXStaticCastExprClass: + case Stmt::CXXStandardLibraryCastExprClass: case Stmt::CXXDynamicCastExprClass: case Stmt::CXXReinterpretCastExprClass: case Stmt::CXXConstCastExprClass: diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -480,6 +480,11 @@ K = CXCursor_CXXStaticCastExpr; break; + case Stmt::CXXStandardLibraryCastExprClass: + return MakeCXCursor( + cast(S)->getOriginalExpression(), Parent, + TU, RegionOfInterest); + case Stmt::CXXDynamicCastExprClass: K = CXCursor_CXXDynamicCastExpr; break;