diff options
-rw-r--r-- | include/clang/AST/ExprCXX.h | 97 | ||||
-rw-r--r-- | include/clang/AST/StmtNodes.def | 1 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 39 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateExpr.cpp | 41 |
6 files changed, 198 insertions, 8 deletions
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index dd6a26e3d3..f3c8244160 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -982,6 +982,103 @@ public: virtual child_iterator child_end(); }; +/// \brief Describes an explicit type conversion that uses functional +/// notion but could not be resolved because one or more arguments are +/// type-dependent. +/// +/// The explicit type conversions expressed by +/// CXXUnresolvedConstructExpr have the form \c T(a1, a2, ..., aN), +/// where \c T is some type and \c a1, a2, ..., aN are values, and +/// either \C T is a dependent type or one or more of the \c a's is +/// type-dependent. For example, this would occur in a template such +/// as: +/// +/// \code +/// template<typename T, typename A1> +/// inline T make_a(const A1& a1) { +/// return T(a1); +/// } +/// \endcode +/// +/// When the returned expression is instantiated, it may resolve to a +/// constructor call, conversion function call, or some kind of type +/// conversion. +class CXXUnresolvedConstructExpr : public Expr { + /// \brief The starting location of the type + SourceLocation TyBeginLoc; + + /// \brief The type being constructed. + QualType Type; + + /// \brief The location of the left parentheses ('('). + SourceLocation LParenLoc; + + /// \brief The location of the right parentheses (')'). + SourceLocation RParenLoc; + + /// \brief The number of arguments used to construct the type. + unsigned NumArgs; + + CXXUnresolvedConstructExpr(SourceLocation TyBegin, + QualType T, + SourceLocation LParenLoc, + Expr **Args, + unsigned NumArgs, + SourceLocation RParenLoc); + +public: + static CXXUnresolvedConstructExpr *Create(ASTContext &C, + SourceLocation TyBegin, + QualType T, + SourceLocation LParenLoc, + Expr **Args, + unsigned NumArgs, + SourceLocation RParenLoc); + + /// \brief Retrieve the source location where the type begins. + SourceLocation getTypeBeginLoc() const { return TyBeginLoc; } + void setTypeBeginLoc(SourceLocation L) { TyBeginLoc = L; } + + /// \brief Retrieve the type that is being constructed, as specified + /// in the source code. + QualType getTypeAsWritten() const { return Type; } + void setTypeAsWritten(QualType T) { Type = T; } + + /// \brief Retrieve the location of the left parentheses ('(') that + /// precedes the argument list. + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + + /// \brief Retrieve the location of the right parentheses (')') that + /// follows the argument list. + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + /// \brief Retrieve the number of arguments. + unsigned arg_size() const { return NumArgs; } + + typedef Expr** arg_iterator; + arg_iterator arg_begin() { return reinterpret_cast<Expr**>(this + 1); } + arg_iterator arg_end() { return arg_begin() + NumArgs; } + + Expr *getArg(unsigned I) { + assert(I < NumArgs && "Argument index out-of-range"); + return *(arg_begin() + I); + } + + virtual SourceRange getSourceRange() const { + return SourceRange(TyBeginLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXUnresolvedConstructExprClass; + } + static bool classof(const CXXUnresolvedConstructExpr *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + } // end namespace clang #endif diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index 03203f2fa8..98e65d5cf9 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -126,6 +126,7 @@ EXPR(UnresolvedDeclRefExpr , Expr) EXPR(CXXConstructExpr , Expr) EXPR(CXXExprWithTemporaries , Expr) EXPR(CXXTemporaryObjectExpr , CXXConstructExpr) +EXPR(CXXUnresolvedConstructExpr, Expr) // Obj-C Expressions. EXPR(ObjCStringLiteral , Expr) diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index a138f01c77..a73843ca36 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -314,6 +314,45 @@ Stmt::child_iterator CXXExprWithTemporaries::child_end() { return &SubExpr + 1; } +CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr( + SourceLocation TyBeginLoc, + QualType T, + SourceLocation LParenLoc, + Expr **Args, + unsigned NumArgs, + SourceLocation RParenLoc) + : Expr(CXXUnresolvedConstructExprClass, T.getNonReferenceType(), + T->isDependentType(), true), + TyBeginLoc(TyBeginLoc), + Type(T), + LParenLoc(LParenLoc), + RParenLoc(RParenLoc), + NumArgs(NumArgs) { + Stmt **StoredArgs = reinterpret_cast<Stmt **>(this + 1); + memcpy(StoredArgs, Args, sizeof(Expr *) * NumArgs); +} + +CXXUnresolvedConstructExpr * +CXXUnresolvedConstructExpr::Create(ASTContext &C, + SourceLocation TyBegin, + QualType T, + SourceLocation LParenLoc, + Expr **Args, + unsigned NumArgs, + SourceLocation RParenLoc) { + void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) + + sizeof(Expr *) * NumArgs); + return new (Mem) CXXUnresolvedConstructExpr(TyBegin, T, LParenLoc, + Args, NumArgs, RParenLoc); +} + +Stmt::child_iterator CXXUnresolvedConstructExpr::child_begin() { + return child_iterator(reinterpret_cast<Stmt **>(this + 1)); +} + +Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() { + return child_iterator(reinterpret_cast<Stmt **>(this + 1) + NumArgs); +} //===----------------------------------------------------------------------===// // Cloners diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 380634daf3..30de402edd 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1110,6 +1110,21 @@ void StmtPrinter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { PrintExpr(E->getSubExpr()); } +void +StmtPrinter::VisitCXXUnresolvedConstructExpr( + CXXUnresolvedConstructExpr *Node) { + OS << Node->getTypeAsWritten().getAsString(); + OS << "("; + for (CXXUnresolvedConstructExpr::arg_iterator Arg = Node->arg_begin(), + ArgEnd = Node->arg_end(); + Arg != ArgEnd; ++Arg) { + if (Arg != Node->arg_begin()) + OS << ", "; + PrintExpr(*Arg); + } + OS << ")"; +} + static const char *getTypeTraitName(UnaryTypeTrait UTT) { switch (UTT) { default: assert(false && "Unknown type trait"); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 30a7598ec6..b9575101b0 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -164,14 +164,11 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep, CallExpr::hasAnyTypeDependentArguments(Exprs, NumExprs)) { exprs.release(); - // FIXME: Is this correct (I don't think so). Instead, we should have an - // CXXUnresolvedTemporaryObjectExpr node for this. - CXXTempVarDecl *Temp = CXXTempVarDecl::Create(Context, CurContext, Ty); - - return Owned(new (Context) CXXTemporaryObjectExpr(Context, Temp, 0, Ty, - TyBeginLoc, - Exprs, NumExprs, - RParenLoc)); + return Owned(CXXUnresolvedConstructExpr::Create(Context, + TypeRange.getBegin(), Ty, + LParenLoc, + Exprs, NumExprs, + RParenLoc)); } diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp index a0e2941e26..1dad862063 100644 --- a/lib/Sema/SemaTemplateInstantiateExpr.cpp +++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp @@ -93,6 +93,8 @@ namespace { // FIXME: UnaryTypeTraitExpr // FIXME: QualifiedDeclRefExpr // FIXME: CXXExprWithTemporaries + OwningExprResult VisitCXXUnresolvedConstructExpr( + CXXUnresolvedConstructExpr *E); OwningExprResult VisitGNUNullExpr(GNUNullExpr *E); OwningExprResult VisitUnresolvedFunctionNameExpr( UnresolvedFunctionNameExpr *E); @@ -834,6 +836,45 @@ TemplateExprInstantiator::VisitCXXThisExpr(CXXThisExpr *E) { } Sema::OwningExprResult +TemplateExprInstantiator::VisitCXXUnresolvedConstructExpr( + CXXUnresolvedConstructExpr *E) { + QualType T = SemaRef.InstantiateType(E->getTypeAsWritten(), TemplateArgs, + E->getTypeBeginLoc(), + DeclarationName()); + if (T.isNull()) + return SemaRef.ExprError(); + + llvm::SmallVector<Expr *, 8> Args; + llvm::SmallVector<SourceLocation, 8> FakeCommaLocs; + for (CXXUnresolvedConstructExpr::arg_iterator Arg = E->arg_begin(), + ArgEnd = E->arg_end(); + Arg != ArgEnd; ++Arg) { + OwningExprResult InstArg = Visit(*Arg); + if (InstArg.isInvalid()) { + for (unsigned I = 0; I != Args.size(); ++I) + Args[I]->Destroy(SemaRef.Context); + return SemaRef.ExprError(); + } + + FakeCommaLocs.push_back( + SemaRef.PP.getLocForEndOfToken((*Arg)->getSourceRange().getEnd())); + Args.push_back(InstArg.takeAs<Expr>()); + } + + // FIXME: The end of the type range isn't exactly correct. + // FIXME: we're faking the locations of the commas + return SemaRef.ActOnCXXTypeConstructExpr(SourceRange(E->getTypeBeginLoc(), + E->getLParenLoc()), + T.getAsOpaquePtr(), + E->getLParenLoc(), + Sema::MultiExprArg(SemaRef, + (void **)&Args.front(), + Args.size()), + &FakeCommaLocs.front(), + E->getRParenLoc()); +} + +Sema::OwningExprResult Sema::InstantiateExpr(Expr *E, const TemplateArgumentList &TemplateArgs) { if (!E) return Owned((Expr *)0); |