From 8dbc2694424b4e842b1d5ea39744a137b58600c3 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 17 Mar 2009 21:15:40 +0000 Subject: [PATCH] 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 --- include/clang/AST/DeclVisitor.h | 49 ++++++ lib/Sema/CMakeLists.txt | 1 + lib/Sema/Sema.h | 4 + lib/Sema/SemaTemplateInstantiate.cpp | 161 ++---------------- lib/Sema/SemaTemplateInstantiateDecl.cpp | 202 +++++++++++++++++++++++ 5 files changed, 268 insertions(+), 149 deletions(-) create mode 100644 include/clang/AST/DeclVisitor.h create mode 100644 lib/Sema/SemaTemplateInstantiateDecl.cpp diff --git a/include/clang/AST/DeclVisitor.h b/include/clang/AST/DeclVisitor.h new file mode 100644 index 0000000000..871b933172 --- /dev/null +++ b/include/clang/AST/DeclVisitor.h @@ -0,0 +1,49 @@ +//===--- DeclVisitor.h - Visitor for Decl subclasses ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DeclVisitor interface. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_DECLVISITOR_H +#define LLVM_CLANG_AST_DECLVISITOR_H + +namespace clang { + +#define DISPATCH(NAME, CLASS) \ + return static_cast(this)-> Visit##NAME(static_cast(D)) + +/// \brief A simple visitor class that helps create declaration visitors. +template +class DeclVisitor { +public: + RetTy Visit(Decl *D) { + switch (D->getKind()) { + default: assert(false && "Decl that isn't part of DeclNodes.def!"); +#define DECL(Derived, Base) \ + case Decl::Derived: DISPATCH(Derived##Decl, Derived##Decl); +#define ABSTRACT_DECL(Derived, Base) +#include "clang/AST/DeclNodes.def" + } + } + + // If the implementation chooses not to implement a certain visit + // method, fall back to the parent. +#define DECL(Derived, Base) \ + RetTy Visit##Derived##Decl(Derived##Decl *D) { DISPATCH(Base, Base); } +#define ABSTRACT_DECL(Derived, Base) DECL(Derived, Base) +#include "clang/AST/DeclNodes.def" + + RetTy VisitDecl(Decl *D) { return RetTy(); } +}; + +#undef DISPATCH + +} // end namespace clang + +#endif // LLVM_CLANG_AST_DECLVISITOR_H diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index e90c7e30c2..28147b2cc1 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -22,6 +22,7 @@ add_clang_library(clangSema SemaStmt.cpp SemaTemplate.cpp SemaTemplateInstantiate.cpp + SemaTemplateInstantiateDecl.cpp SemaType.cpp ) diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index ed6b2d4160..fae0fa680c 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1864,6 +1864,10 @@ public: const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); + Decl *InstantiateDecl(Decl *D, DeclContext *Owner, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + bool InstantiateBaseSpecifiers(ClassTemplateSpecializationDecl *ClassTemplateSpec, ClassTemplateDecl *ClassTemplate); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 4f0a9923bd..cdb7f083df 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1036,7 +1036,6 @@ Sema::InstantiateClassTemplateSpecialization( // Start the definition of this instantiation. ClassTemplateSpec->startDefinition(); - // Instantiate the base class specifiers. if (InstantiateBaseSpecifiers(ClassTemplateSpec, Template)) Invalid = true; @@ -1049,155 +1048,19 @@ Sema::InstantiateClassTemplateSpecialization( for (RecordDecl::decl_iterator Member = Pattern->decls_begin(), MemberEnd = Pattern->decls_end(); Member != MemberEnd; ++Member) { - if (TypedefDecl *Typedef = dyn_cast(*Member)) { - // FIXME: Simplified instantiation of typedefs needs to be made - // "real". - QualType T = Typedef->getUnderlyingType(); - if (T->isDependentType()) { - T = InstantiateType(T, ClassTemplateSpec->getTemplateArgs(), - ClassTemplateSpec->getNumTemplateArgs(), - Typedef->getLocation(), - Typedef->getDeclName()); - if (T.isNull()) { - Invalid = true; - T = Context.IntTy; - } - } - - // Create the new typedef - TypedefDecl *New - = TypedefDecl::Create(Context, ClassTemplateSpec, - Typedef->getLocation(), - Typedef->getIdentifier(), - T); - ClassTemplateSpec->addDecl(New); - } - else if (FieldDecl *Field = dyn_cast(*Member)) { - // FIXME: Simplified instantiation of fields needs to be made - // "real". - bool InvalidDecl = false; - QualType T = Field->getType(); - if (T->isDependentType()) { - T = InstantiateType(T, ClassTemplateSpec->getTemplateArgs(), - ClassTemplateSpec->getNumTemplateArgs(), - Field->getLocation(), - Field->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. - Diag(Field->getLocation(), diag::err_field_instantiates_to_function) - << T; - T = QualType(); - InvalidDecl = true; - } - } - - Expr *BitWidth = Field->getBitWidth(); - if (InvalidDecl) - BitWidth = 0; - else if (BitWidth) { - OwningExprResult InstantiatedBitWidth - = InstantiateExpr(BitWidth, - ClassTemplateSpec->getTemplateArgs(), - ClassTemplateSpec->getNumTemplateArgs()); - if (InstantiatedBitWidth.isInvalid()) { - Invalid = InvalidDecl = true; - BitWidth = 0; - } else - BitWidth = (Expr *)InstantiatedBitWidth.release(); - } - - FieldDecl *New = CheckFieldDecl(Field->getDeclName(), T, - ClassTemplateSpec, - Field->getLocation(), - Field->isMutable(), - BitWidth, - Field->getAccess(), - 0); - if (New) { - ClassTemplateSpec->addDecl(New); - Fields.push_back(New); - - if (InvalidDecl) - New->setInvalidDecl(); - - if (New->isInvalidDecl()) - Invalid = true; - } - } else if (StaticAssertDecl *SA = dyn_cast(*Member)) { - Expr *AssertExpr = SA->getAssertExpr(); - - OwningExprResult InstantiatedAssertExpr - = InstantiateExpr(AssertExpr, - ClassTemplateSpec->getTemplateArgs(), - ClassTemplateSpec->getNumTemplateArgs()); - if (!InstantiatedAssertExpr.isInvalid()) { - OwningExprResult Message = Clone(SA->getMessage()); - - Decl *New = - (Decl *)ActOnStaticAssertDeclaration(SA->getLocation(), - move(InstantiatedAssertExpr), - move(Message)); - if (New->isInvalidDecl()) - Invalid = true; - - } else + Decl *NewMember = InstantiateDecl(*Member, ClassTemplateSpec, + ClassTemplateSpec->getTemplateArgs(), + ClassTemplateSpec->getNumTemplateArgs()); + if (NewMember) { + if (NewMember->isInvalidDecl()) Invalid = true; - } else if (EnumDecl *Enum = dyn_cast(*Member)) { - // FIXME: Spaghetti, anyone? - EnumDecl *New = EnumDecl::Create(Context, ClassTemplateSpec, - Enum->getLocation(), - Enum->getIdentifier(), - /*PrevDecl=*/0); - ClassTemplateSpec->addDecl(New); - New->startDefinition(); - - llvm::SmallVector Enumerators; - - EnumConstantDecl *LastEnumConst = 0; - for (EnumDecl::enumerator_iterator EC = Enum->enumerator_begin(), - ECEnd = Enum->enumerator_end(); - EC != ECEnd; ++EC) { - // The specified value for the enumerator. - OwningExprResult Value = Owned((Expr *)0); - if (Expr *UninstValue = EC->getInitExpr()) - Value = InstantiateExpr(UninstValue, - ClassTemplateSpec->getTemplateArgs(), - ClassTemplateSpec->getNumTemplateArgs()); - - // Drop the initial value and continue. - bool isInvalid = false; - if (Value.isInvalid()) { - Value = Owned((Expr *)0); - isInvalid = true; - } - - EnumConstantDecl *NewEnumConst - = CheckEnumConstant(New, LastEnumConst, - EC->getLocation(), - EC->getIdentifier(), - move(Value)); - - if (isInvalid) { - if (NewEnumConst) - NewEnumConst->setInvalidDecl(); - New->setInvalidDecl(); - Invalid = true; - } - - if (NewEnumConst) { - New->addDecl(NewEnumConst); - Enumerators.push_back(NewEnumConst); - LastEnumConst = NewEnumConst; - } - } - - ActOnEnumBody(New->getLocation(), New, - &Enumerators[0], Enumerators.size()); + else if (FieldDecl *Field = dyn_cast(NewMember)) + Fields.push_back(Field); + } else { + // FIXME: Eventually, a NULL return will mean that one of the + // instantiations was a semantic disaster, and we'll want to set + // Invalid = true. For now, we expect to skip some members that + // we can't yet handle. } } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp new file mode 100644 index 0000000000..906ea25822 --- /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 + { + 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(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 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); +} + -- 2.40.0