diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-06-22 23:06:13 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-06-22 23:06:13 +0000 |
commit | d7f37bf8b9a211455c5037df7b7e88e5a9510119 (patch) | |
tree | 3e2f8b4bdfc41b7836ecf45752dbce8b5e831fde | |
parent | 2f96a0679a8d9c05fd3634340421f2d360701059 (diff) |
Implement implicit instantiation of the member functions of a class template
specialization. At present, all implicit instantiations occur at the
end of the translation unit.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73915 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 19 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 30 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 17 | ||||
-rw-r--r-- | test/CodeGenCXX/implicit-instantiation-1.cpp | 29 | ||||
-rw-r--r-- | test/SemaTemplate/example-dynarray.cpp | 28 |
8 files changed, 124 insertions, 14 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 69152523a1..426f56f438 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -273,7 +273,7 @@ AttributeList* Parser::ParseMicrosoftTypeAttributes(AttributeList *CurrAttr) { /// [C++] template-declaration /// [C++] namespace-definition /// [C++] using-directive -/// [C++] using-declaration [TODO] +/// [C++] using-declaration /// [C++0x] static_assert-declaration /// others... [FIXME] /// diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 2fa09b9046..c37f66dae9 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -235,6 +235,18 @@ void Sema::DeleteStmt(StmtTy *S) { /// translation unit when EOF is reached and all but the top-level scope is /// popped. void Sema::ActOnEndOfTranslationUnit() { + // C++: Perform implicit template instantiations. + // + // FIXME: When we perform these implicit instantiations, we do not carefully + // keep track of the point of instantiation (C++ [temp.point]). This means + // that name lookup that occurs within the template instantiation will + // always happen at the end of the translation unit, so it will find + // some names that should not be found. Although this is common behavior + // for C++ compilers, it is technically wrong. In the future, we either need + // to be able to filter the results of name lookup or we need to perform + // template instantiations earlier. + PerformPendingImplicitInstantiations(); + if (!CompleteTranslationUnit) return; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 28f81e614a..e5502a5937 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -31,6 +31,7 @@ #include "llvm/ADT/OwningPtr.h" #include <list> #include <string> +#include <queue> #include <vector> namespace llvm { @@ -2504,6 +2505,22 @@ public: /// variables. LocalInstantiationScope *CurrentInstantiationScope; + /// \brief An entity for which implicit template instantiation is required. + /// + /// The source location associated with the declaration is the first place in + /// the source code where the declaration was "used". It is not necessarily + /// the point of instantiation (which will be either before or after the + /// namespace-scope declaration that triggered this implicit instantiation), + /// However, it is the location that diagnostics should generally refer to, + /// because users will need to know what code triggered the instantiation. + typedef std::pair<ValueDecl *, SourceLocation> PendingImplicitInstantiation; + + /// \brief The queue of implicit template instantiations that are required + /// but have not yet been performed. + std::queue<PendingImplicitInstantiation> PendingImplicitInstantiations; + + void PerformPendingImplicitInstantiations(); + QualType InstantiateType(QualType T, const TemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); @@ -2559,7 +2576,7 @@ public: void InstantiateVariableDefinition(VarDecl *Var); NamedDecl *InstantiateCurrentDeclRef(NamedDecl *D); - + // Simple function for cloning expressions. template<typename T> OwningExprResult Clone(T *E) { diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 04c569a528..e8265d9ad9 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1921,6 +1921,7 @@ void Sema::InitializeVarWithConstructor(VarDecl *VD, Expr **Exprs, unsigned NumExprs) { Expr *Temp = CXXConstructExpr::Create(Context, DeclInitType, Constructor, false, Exprs, NumExprs); + MarkDeclarationReferenced(VD->getLocation(), Constructor); VD->setInit(Context, Temp); } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index c005f103a3..81765a57d6 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -2134,25 +2134,32 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, MemberType = MemberType.getQualifiedType(combinedQualifiers); } + MarkDeclarationReferenced(MemberLoc, FD); return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, FD, MemberLoc, MemberType)); } - if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) + if (VarDecl *Var = dyn_cast<VarDecl>(MemberDecl)) { + MarkDeclarationReferenced(MemberLoc, MemberDecl); return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, Var, MemberLoc, Var->getType().getNonReferenceType())); - if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) + } + if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) { + MarkDeclarationReferenced(MemberLoc, MemberDecl); return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, MemberFn, MemberLoc, MemberFn->getType())); + } if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(MemberDecl)) return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, Ovl, MemberLoc, Context.OverloadTy)); - if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) + if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(MemberDecl)) { + MarkDeclarationReferenced(MemberLoc, MemberDecl); return Owned(new (Context) MemberExpr(BaseExpr, OpKind == tok::arrow, Enum, MemberLoc, Enum->getType())); + } if (isa<TypeDecl>(MemberDecl)) return ExprError(Diag(MemberLoc,diag::err_typecheck_member_reference_type) << DeclarationName(&Member) << int(OpKind == tok::arrow)); @@ -5475,6 +5482,9 @@ Sema::PopExpressionEvaluationContext(ExpressionEvaluationContext OldContext, void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { assert(D && "No declaration?"); + if (D->isUsed()) + return; + // Mark a parameter declaration "used", regardless of whether we're in a // template or not. if (isa<ParmVarDecl>(D)) @@ -5512,16 +5522,22 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { // FIXME: more checking for other implicits go here. else Constructor->setUsed(true); - return; } if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { - // FIXME: implicit template instantiation + // Implicit instantiation of function templates + if (!Function->getBody(Context)) { + if (Function->getInstantiatedFromMemberFunction()) + PendingImplicitInstantiations.push(std::make_pair(Function, Loc)); + + // FIXME: check for function template specializations. + } + + // FIXME: keep track of references to static functions - (void)Function; Function->setUsed(true); return; - } + } if (VarDecl *Var = dyn_cast<VarDecl>(D)) { (void)Var; diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 461302f81d..ece71bc0d3 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -597,6 +597,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (Function->isInvalidDecl()) return; + assert(!Function->getBody(Context) && "Already instantiated!"); + // Find the function body that we'll be substituting. const FunctionDecl *PatternDecl = Function->getInstantiatedFromMemberFunction(); @@ -776,3 +778,18 @@ NamedDecl * Sema::InstantiateCurrentDeclRef(NamedDecl *D) { return D; } + +/// \brief Performs template instantiation for all implicit template +/// instantiations we have seen until this point. +void Sema::PerformPendingImplicitInstantiations() { + while (!PendingImplicitInstantiations.empty()) { + PendingImplicitInstantiation Inst = PendingImplicitInstantiations.front(); + PendingImplicitInstantiations.pop(); + + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) + if (!Function->getBody(Context)) + InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function); + + // FIXME: instantiation static member variables + } +} diff --git a/test/CodeGenCXX/implicit-instantiation-1.cpp b/test/CodeGenCXX/implicit-instantiation-1.cpp new file mode 100644 index 0000000000..f6c6114d20 --- /dev/null +++ b/test/CodeGenCXX/implicit-instantiation-1.cpp @@ -0,0 +1,29 @@ +// RUN: clang-cc -emit-llvm %s -o %t && + +template<typename T> +struct X { + void f(T) { } + void f(char) { } + + void g(T) { } + + void h(T) { } +}; + +void foo(X<int> &xi, X<float> *xfp, int i, float f) { + // RUN: grep "linkonce_odr.*_ZN1XIiE1fEi" %t | count 1 && + xi.f(i); + + // RUN: grep "linkonce_odr.*_ZN1XIiE1gEi" %t | count 1 && + xi.g(f); + + // RUN: grep "linkonce_odr.*_ZN1XIfE1fEf" %t | count 1 && + xfp->f(f); + + // RUN: grep "linkonce_odr.*_ZN1XIfE1hEf" %t | count 0 && + + // RUN: true +} + + + diff --git a/test/SemaTemplate/example-dynarray.cpp b/test/SemaTemplate/example-dynarray.cpp index cca3709beb..680ee04ba1 100644 --- a/test/SemaTemplate/example-dynarray.cpp +++ b/test/SemaTemplate/example-dynarray.cpp @@ -89,6 +89,21 @@ public: iterator end() { return Last; } const_iterator end() const { return Last; } + bool operator==(const dynarray &other) const { + if (size() != other.size()) + return false; + + for (unsigned I = 0, N = size(); I != N; ++I) + if ((*this)[I] != other[I]) + return false; + + return true; + } + + bool operator!=(const dynarray &other) const { + return !(*this == other); + } + public: T* Start, *Last, *End; }; @@ -100,11 +115,6 @@ struct Point { float x, y, z; }; -// FIXME: remove these when we have implicit instantiation for member -// functions of class templates. -template class dynarray<int>; -template class dynarray<Point>; - int main() { dynarray<int> di; di.push_back(0); @@ -146,5 +156,13 @@ int main() { I != IEnd; ++I) assert(*I == I - di4.begin()); + assert(di4 == di); + di4[3] = 17; + assert(di4 != di); + + dynarray<Point> dp; + dp.push_back(Point()); + assert(dp.size() == 1); + return 0; } |