diff options
-rw-r--r-- | include/clang/AST/ExprCXX.h | 2 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateExpr.cpp | 65 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-call.cpp | 50 |
4 files changed, 113 insertions, 9 deletions
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index d9cd35836b..1847755a98 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -800,6 +800,8 @@ public: virtual SourceRange getSourceRange() const { return SourceRange(Loc); } + UnresolvedFunctionNameExpr* Clone(ASTContext &C) const; + static bool classof(const Stmt *T) { return T->getStmtClass() == UnresolvedFunctionNameExprClass; } diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 71617c4df2..a138f01c77 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -131,6 +131,11 @@ Stmt::child_iterator UnresolvedFunctionNameExpr::child_end() { return child_iterator(); } +UnresolvedFunctionNameExpr* +UnresolvedFunctionNameExpr::Clone(ASTContext &C) const { + return new (C) UnresolvedFunctionNameExpr(Name, getType(), Loc); +} + // UnaryTypeTraitExpr Stmt::child_iterator UnaryTypeTraitExpr::child_begin() { return child_iterator(); diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp index 41df7aba29..95b2a29523 100644 --- a/lib/Sema/SemaTemplateInstantiateExpr.cpp +++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp @@ -46,6 +46,7 @@ namespace { OwningExprResult VisitParenExpr(ParenExpr *E); OwningExprResult VisitUnaryOperator(UnaryOperator *E); OwningExprResult VisitArraySubscriptExpr(ArraySubscriptExpr *E); + OwningExprResult VisitCallExpr(CallExpr *E); OwningExprResult VisitBinaryOperator(BinaryOperator *E); OwningExprResult VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); OwningExprResult VisitCXXConditionDeclExpr(CXXConditionDeclExpr *E); @@ -58,6 +59,8 @@ namespace { OwningExprResult VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E); OwningExprResult VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E); OwningExprResult VisitGNUNullExpr(GNUNullExpr *E); + OwningExprResult VisitUnresolvedFunctionNameExpr( + UnresolvedFunctionNameExpr *E); // Base case. I'm supposed to ignore this. Sema::OwningExprResult VisitStmt(Stmt *S) { @@ -113,9 +116,16 @@ TemplateExprInstantiator::VisitGNUNullExpr(GNUNullExpr *E) { return SemaRef.Clone(E); } +Sema::OwningExprResult +TemplateExprInstantiator::VisitUnresolvedFunctionNameExpr( + UnresolvedFunctionNameExpr *E) { + return SemaRef.Clone(E); +} + Sema::OwningExprResult TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) { Decl *D = E->getDecl(); + ValueDecl *NewD = 0; if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { assert(NTTP->getDepth() == 0 && "No nested templates yet"); const TemplateArgument &Arg = TemplateArgs[NTTP->getPosition()]; @@ -136,19 +146,23 @@ TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) { *Arg.getAsIntegral(), T, E->getSourceRange().getBegin())); - } else if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) { - ParmVarDecl *ParmInst - = SemaRef.CurrentInstantiationScope->getInstantiationOf(Parm); - QualType T = ParmInst->getType(); - return SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(ParmInst, + } else if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) + NewD = SemaRef.CurrentInstantiationScope->getInstantiationOf(Parm); + else if (isa<FunctionDecl>(D) || isa<OverloadedFunctionDecl>(D)) + // FIXME: Instantiate decl! + NewD = cast<ValueDecl>(D); + else + assert(false && "Unhandled declaratrion reference kind"); + + if (!NewD) + return SemaRef.ExprError(); + + QualType T = NewD->getType(); + return SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(NewD, T.getNonReferenceType(), E->getLocation(), T->isDependentType(), T->isDependentType())); - } else - assert(false && "Can't handle arbitrary declaration references"); - - return SemaRef.ExprError(); } Sema::OwningExprResult @@ -203,6 +217,39 @@ TemplateExprInstantiator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { E->getRBracketLoc()); } +Sema::OwningExprResult TemplateExprInstantiator::VisitCallExpr(CallExpr *E) { + // Instantiate callee + OwningExprResult Callee = Visit(E->getCallee()); + if (Callee.isInvalid()) + return SemaRef.ExprError(); + + // Instantiate arguments + llvm::SmallVector<Expr*, 8> Args; + llvm::SmallVector<SourceLocation, 4> FakeCommaLocs; + for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) { + OwningExprResult Arg = Visit(E->getArg(I)); + if (Arg.isInvalid()) { + for (unsigned Victim = 0; Victim != I; ++Victim) + Args[Victim]->Destroy(SemaRef.Context); + return SemaRef.ExprError(); + } + + FakeCommaLocs.push_back( + SemaRef.PP.getLocForEndOfToken(E->getArg(I)->getSourceRange().getEnd())); + Args.push_back(Arg.takeAs<Expr>()); + } + + SourceLocation FakeLParenLoc + = ((Expr *)Callee.get())->getSourceRange().getBegin(); + return SemaRef.ActOnCallExpr(/*Scope=*/0, move(Callee), + /*FIXME:*/FakeLParenLoc, + Sema::MultiExprArg(SemaRef, + (void **)&Args.front(), + Args.size()), + /*FIXME:*/&FakeCommaLocs.front(), + E->getRParenLoc()); +} + Sema::OwningExprResult TemplateExprInstantiator::VisitBinaryOperator(BinaryOperator *E) { Sema::OwningExprResult LHS = Visit(E->getLHS()); diff --git a/test/SemaTemplate/instantiate-call.cpp b/test/SemaTemplate/instantiate-call.cpp new file mode 100644 index 0000000000..a9c4bf481d --- /dev/null +++ b/test/SemaTemplate/instantiate-call.cpp @@ -0,0 +1,50 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +namespace N1 { + struct X0 { }; + + int& f0(X0); +} + +namespace N2 { + char& f0(char); + + template<typename T, typename Result> + struct call_f0 { + void test_f0(T t) { + Result result = f0(t); + } + }; +} + +template struct N2::call_f0<int, char&>; +template struct N2::call_f0<N1::X0, int&>; + +namespace N3 { + template<typename T, typename Result> + struct call_f0 { + void test_f0(T t) { + Result &result = f0(t); // expected-error 2{{no matching}} + } + }; +} + +template struct N3::call_f0<int, char&>; // expected-note{{instantiation}} +template struct N3::call_f0<N1::X0, int&>; + +short& f0(char); +namespace N4 { + template<typename T, typename Result> + struct call_f0 { + void test_f0(T t) { + Result &result = f0(t); + } + }; +} + +template struct N4::call_f0<int, short&>; +template struct N4::call_f0<N1::X0, int&>; +template struct N3::call_f0<int, short&>; // expected-note{{instantiation}} + +// FIXME: test overloaded function call operators, calls to member +// functions, etc. |