/// wasting space in the Decl class.
llvm::DenseMap<const Decl*, Attr*> DeclAttrs;
+ /// \brief Keeps track of the static data member templates from which
+ /// static data members of class template specializations were instantiated.
+ ///
+ /// This data structure stores the mapping from instantiations of static
+ /// data members to the static data member representations within the
+ /// class template from which they were instantiated.
+ ///
+ /// Given the following example:
+ ///
+ /// \code
+ /// template<typename T>
+ /// struct X {
+ /// static T value;
+ /// };
+ ///
+ /// template<typename T>
+ /// T X<T>::value = T(17);
+ ///
+ /// int *x = &X<int>::value;
+ /// \endcode
+ ///
+ /// This mapping will contain an entry that maps from the VarDecl for
+ /// X<int>::value to the corresponding VarDecl for X<T>::value (within the
+ /// class template X).
+ llvm::DenseMap<VarDecl *, VarDecl *> InstantiatedFromStaticDataMember;
+
TranslationUnitDecl *TUDecl;
/// SourceMgr - The associated SourceManager object.
/// \brief Erase the attributes corresponding to the given declaration.
void eraseDeclAttrs(const Decl *D) { DeclAttrs.erase(D); }
+ /// \brief If this variable is an instantiated static data member of a
+ /// class template specialization, returns the templated static data member
+ /// from which it was instantiated.
+ VarDecl *getInstantiatedFromStaticDataMember(VarDecl *Var);
+
+ /// \brief Note that the static data member \p Inst is an instantiation of
+ /// the static data member template \p Tmpl of a class template.
+ void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl);
+
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
const char *getCommentForDecl(const Decl *D);
Var->setCXXDirectInitializer(D->hasCXXDirectInitializer());
Var->setDeclaredInCondition(D->isDeclaredInCondition());
+ // If we are instantiating a static data member defined
+ // out-of-line, the instantiation will have the same lexical
+ // context (which will be a namespace scope) as the template.
+ if (D->isOutOfLine())
+ Var->setLexicalDeclContext(D->getLexicalDeclContext());
+
// FIXME: In theory, we could have a previous declaration for variables that
// are not static data members.
bool Redeclaration = false;
SemaRef.CheckVariableDeclaration(Var, 0, Redeclaration);
- Owner->addDecl(Var);
-
+
+ if (D->isOutOfLine()) {
+ D->getLexicalDeclContext()->addDecl(Var);
+ Owner->makeDeclVisibleInContext(Var);
+ } else {
+ Owner->addDecl(Var);
+ }
+
if (D->getInit()) {
OwningExprResult Init
= SemaRef.InstantiateExpr(D->getInit(), TemplateArgs);
// FIXME: Call ActOnUninitializedDecl? (Not always)
}
+ // Link instantiations of static data members back to the template from
+ // which they were instantiated.
+ if (Var->isStaticDataMember())
+ SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D);
+
return Var;
}
D->isInline());
Method->setInstantiationOfMemberFunction(D);
+ // If we are instantiating a member function defined
+ // out-of-line, the instantiation will have the same lexical
+ // context (which will be a namespace scope) as the template.
+ if (D->isOutOfLine())
+ Method->setLexicalDeclContext(D->getLexicalDeclContext());
+
// Attach the parameters
for (unsigned P = 0; P < Params.size(); ++P)
Params[P]->setOwningFunction(Method);
/// \brief Instantiate the definition of the given variable from its
/// template.
///
-/// \param Var the already-instantiated declaration of a variable.
-void Sema::InstantiateVariableDefinition(VarDecl *Var) {
- // FIXME: Implement this!
+/// \param PointOfInstantiation the point at which the instantiation was
+/// required. Note that this is not precisely a "point of instantiation"
+/// for the function, but it's close.
+///
+/// \param Var the already-instantiated declaration of a static member
+/// variable of a class template specialization.
+///
+/// \param Recursive if true, recursively instantiates any functions that
+/// are required by this instantiation.
+void Sema::InstantiateStaticDataMemberDefinition(
+ SourceLocation PointOfInstantiation,
+ VarDecl *Var,
+ bool Recursive) {
+ if (Var->isInvalidDecl())
+ return;
+
+ // Find the out-of-line definition of this static data member.
+ // FIXME: Do we have to look for specializations separately?
+ VarDecl *Def = Var->getInstantiatedFromStaticDataMember();
+ bool FoundOutOfLineDef = false;
+ assert(Def && "This data member was not instantiated from a template?");
+ assert(Def->isStaticDataMember() && "Not a static data member?");
+ for (VarDecl::redecl_iterator RD = Def->redecls_begin(),
+ RDEnd = Def->redecls_end();
+ RD != RDEnd; ++RD) {
+ if (RD->getLexicalDeclContext()->isFileContext()) {
+ Def = *RD;
+ FoundOutOfLineDef = true;
+ }
+ }
+
+ if (!FoundOutOfLineDef) {
+ // We did not find an out-of-line definition of this static data member,
+ // so we won't perform any instantiation. Rather, we rely on the user to
+ // instantiate this definition (or provide a specialization for it) in
+ // another translation unit.
+ return;
+ }
+
+ InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
+ if (Inst)
+ return;
+
+ // If we're performing recursive template instantiation, create our own
+ // queue of pending implicit instantiations that we will instantiate later,
+ // while we're still within our own instantiation context.
+ std::deque<PendingImplicitInstantiation> SavedPendingImplicitInstantiations;
+ if (Recursive)
+ PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
+
+ // Enter the scope of this instantiation. We don't use
+ // PushDeclContext because we don't have a scope.
+ DeclContext *PreviousContext = CurContext;
+ CurContext = Var->getDeclContext();
+
+#if 0
+ // Instantiate the initializer of this static data member.
+ OwningExprResult Init
+ = InstantiateExpr(Def->getInit(), getTemplateInstantiationArgs(Var));
+ if (Init.isInvalid()) {
+ // If instantiation of the initializer failed, mark the declaration invalid
+ // and don't instantiate anything else that was triggered by this
+ // instantiation.
+ Var->setInvalidDecl();
+
+ // Restore the set of pending implicit instantiations.
+ PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
+
+ return;
+ }
+
+ // Type-check the initializer.
+ if (Init.get())
+ AddInitializerToDecl(DeclPtrTy::make(Var), move(Init),
+ Def->hasCXXDirectInitializer());
+ else
+ ActOnUninitializedDecl(DeclPtrTy::make(Var), false);
+#else
+ Var = cast_or_null<VarDecl>(InstantiateDecl(Def, Var->getDeclContext(),
+ getTemplateInstantiationArgs(Var)));
+#endif
+
+ CurContext = PreviousContext;
+
+ if (Var) {
+ DeclGroupRef DG(Var);
+ Consumer.HandleTopLevelDecl(DG);
+ }
+
+ if (Recursive) {
+ // Instantiate any pending implicit instantiations found during the
+ // instantiation of this template.
+ PerformPendingImplicitInstantiations();
+
+ // Restore the set of pending implicit instantiations.
+ PendingImplicitInstantiations.swap(SavedPendingImplicitInstantiations);
+ }
}
static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
return Enum->getInstantiatedFromMemberEnum()->getCanonicalDecl()
== D->getCanonicalDecl();
+ if (VarDecl *Var = dyn_cast<VarDecl>(Other))
+ if (Var->isStaticDataMember())
+ return Var->getInstantiatedFromStaticDataMember()->getCanonicalDecl()
+ == D->getCanonicalDecl();
+
// FIXME: How can we find instantiations of anonymous unions?
return D->getDeclName() && isa<NamedDecl>(Other) &&
PendingImplicitInstantiation Inst = PendingImplicitInstantiations.front();
PendingImplicitInstantiations.pop_front();
- if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first))
+ // Instantiate function definitions
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) {
if (!Function->getBody())
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true);
+ continue;
+ }
- // FIXME: instantiate static member variables
+ // Instantiate static data member definitions.
+ VarDecl *Var = cast<VarDecl>(Inst.first);
+ assert(Var->isStaticDataMember() && "Not a static data member?");
+ InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true);
}
}