Refactor instantiation of declarations within a template into a much
cleaner visitor framework.
Added a visitor for declarations, which is quite similar to the
visitor for statatements.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67104 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
new file mode 100644
index 0000000..906ea25
--- /dev/null
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -0,0 +1,202 @@
+//===--- SemaTemplateInstantiateDecl.cpp - C++ Template Decl Instantiation ===/
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===/
+//
+// This file implements C++ template instantiation for declarations.
+//
+//===----------------------------------------------------------------------===/
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/Expr.h"
+#include "llvm/Support/Compiler.h"
+
+using namespace clang;
+
+namespace {
+ class VISIBILITY_HIDDEN TemplateDeclInstantiator
+ : public DeclVisitor<TemplateDeclInstantiator, Decl *>
+ {
+ Sema &SemaRef;
+ DeclContext *Owner;
+ const TemplateArgument *TemplateArgs;
+ unsigned NumTemplateArgs;
+
+ public:
+ typedef Sema::OwningExprResult OwningExprResult;
+
+ TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs)
+ : SemaRef(SemaRef), Owner(Owner), TemplateArgs(TemplateArgs),
+ NumTemplateArgs(NumTemplateArgs) { }
+
+ // FIXME: Once we get closer to completion, replace these
+ // manually-written declarations with automatically-generated ones
+ // from clang/AST/DeclNodes.def.
+ Decl *VisitTypedefDecl(TypedefDecl *D);
+ Decl *VisitFieldDecl(FieldDecl *D);
+ Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
+ Decl *VisitEnumDecl(EnumDecl *D);
+
+ // Base case. FIXME: Remove once we can instantiate everything.
+ Decl *VisitDecl(Decl *) {
+ return 0;
+ }
+ };
+}
+
+Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
+ bool Invalid = false;
+ QualType T = D->getUnderlyingType();
+ if (T->isDependentType()) {
+ T = SemaRef.InstantiateType(T, TemplateArgs, NumTemplateArgs,
+ D->getLocation(),
+ D->getDeclName());
+ if (T.isNull()) {
+ Invalid = true;
+ T = SemaRef.Context.IntTy;
+ }
+ }
+
+ // Create the new typedef
+ TypedefDecl *Typedef
+ = TypedefDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ D->getIdentifier(), T);
+ if (Invalid)
+ Typedef->setInvalidDecl();
+
+ Owner->addDecl(Typedef);
+ return Typedef;
+}
+
+Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
+ bool Invalid = false;
+ QualType T = D->getType();
+ if (T->isDependentType()) {
+ T = SemaRef.InstantiateType(T, TemplateArgs, NumTemplateArgs,
+ D->getLocation(),
+ D->getDeclName());
+ if (!T.isNull() && T->isFunctionType()) {
+ // C++ [temp.arg.type]p3:
+ // If a declaration acquires a function type through a type
+ // dependent on a template-parameter and this causes a
+ // declaration that does not use the syntactic form of a
+ // function declarator to have function type, the program is
+ // ill-formed.
+ SemaRef.Diag(D->getLocation(), diag::err_field_instantiates_to_function)
+ << T;
+ T = QualType();
+ Invalid = true;
+ }
+ }
+
+ Expr *BitWidth = D->getBitWidth();
+ if (Invalid)
+ BitWidth = 0;
+ else if (BitWidth) {
+ OwningExprResult InstantiatedBitWidth
+ = SemaRef.InstantiateExpr(BitWidth, TemplateArgs, NumTemplateArgs);
+ if (InstantiatedBitWidth.isInvalid()) {
+ Invalid = true;
+ BitWidth = 0;
+ } else
+ BitWidth = (Expr *)InstantiatedBitWidth.release();
+ }
+
+ FieldDecl *Field = SemaRef.CheckFieldDecl(D->getDeclName(), T,
+ cast<RecordDecl>(Owner),
+ D->getLocation(),
+ D->isMutable(),
+ BitWidth,
+ D->getAccess(),
+ 0);
+ if (Field) {
+ if (Invalid)
+ Field->setInvalidDecl();
+
+ Owner->addDecl(Field);
+ }
+
+ return Field;
+}
+
+Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) {
+ Expr *AssertExpr = D->getAssertExpr();
+
+ OwningExprResult InstantiatedAssertExpr
+ = SemaRef.InstantiateExpr(AssertExpr, TemplateArgs, NumTemplateArgs);
+ if (InstantiatedAssertExpr.isInvalid())
+ return 0;
+
+ OwningExprResult Message = SemaRef.Clone(D->getMessage());
+ Decl *StaticAssert
+ = (Decl *)SemaRef.ActOnStaticAssertDeclaration(D->getLocation(),
+ move(InstantiatedAssertExpr),
+ move(Message));
+ return StaticAssert;
+}
+
+Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
+ EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner,
+ D->getLocation(), D->getIdentifier(),
+ /*PrevDecl=*/0);
+ Owner->addDecl(Enum);
+ Enum->startDefinition();
+
+ llvm::SmallVector<Sema::DeclTy *, 16> Enumerators;
+
+ EnumConstantDecl *LastEnumConst = 0;
+ for (EnumDecl::enumerator_iterator EC = D->enumerator_begin(),
+ ECEnd = D->enumerator_end();
+ EC != ECEnd; ++EC) {
+ // The specified value for the enumerator.
+ OwningExprResult Value = SemaRef.Owned((Expr *)0);
+ if (Expr *UninstValue = EC->getInitExpr())
+ Value = SemaRef.InstantiateExpr(UninstValue,
+ TemplateArgs, NumTemplateArgs);
+
+ // Drop the initial value and continue.
+ bool isInvalid = false;
+ if (Value.isInvalid()) {
+ Value = SemaRef.Owned((Expr *)0);
+ isInvalid = true;
+ }
+
+ EnumConstantDecl *EnumConst
+ = SemaRef.CheckEnumConstant(Enum, LastEnumConst,
+ EC->getLocation(), EC->getIdentifier(),
+ move(Value));
+
+ if (isInvalid) {
+ if (EnumConst)
+ EnumConst->setInvalidDecl();
+ Enum->setInvalidDecl();
+ }
+
+ if (EnumConst) {
+ Enum->addDecl(EnumConst);
+ Enumerators.push_back(EnumConst);
+ LastEnumConst = EnumConst;
+ }
+ }
+
+ SemaRef.ActOnEnumBody(Enum->getLocation(), Enum,
+ &Enumerators[0], Enumerators.size());
+
+ return Enum;
+}
+
+Decl *Sema::InstantiateDecl(Decl *D, DeclContext *Owner,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
+ TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs,
+ NumTemplateArgs);
+ return Instantiator.Visit(D);
+}
+