summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/DeclCXX.cpp22
-rw-r--r--clang/lib/Sema/Sema.h18
-rw-r--r--clang/lib/Sema/SemaDecl.cpp3
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp169
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp19
-rw-r--r--clang/lib/Sema/SemaType.cpp25
6 files changed, 178 insertions, 78 deletions
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 33e870bc0d6..98d7d8f4873 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/Basic/IdentifierTable.h"
@@ -28,7 +29,8 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
Aggregate(true), PlainOldData(true), Polymorphic(false), Abstract(false),
- Bases(0), NumBases(0), Conversions(DC, DeclarationName()) { }
+ Bases(0), NumBases(0), Conversions(DC, DeclarationName()),
+ TemplateOrInstantiation() { }
CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
@@ -177,6 +179,24 @@ void CXXRecordDecl::addConversionFunction(ASTContext &Context,
Conversions.addOverload(ConvDecl);
}
+CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() {
+ if (TemplateOrInstantiation.getInt() == 1)
+ return cast_or_null<CXXRecordDecl>(TemplateOrInstantiation.getPointer());
+ return 0;
+}
+
+void CXXRecordDecl::setDescribedClassTemplate(ClassTemplateDecl *Template) {
+ TemplateOrInstantiation.setInt(0);
+ TemplateOrInstantiation.setPointer(Template);
+}
+
+ClassTemplateDecl *CXXRecordDecl::getDescribedClassTemplate() {
+ if (TemplateOrInstantiation.getInt() == 0)
+ return cast_or_null<ClassTemplateDecl>(
+ TemplateOrInstantiation.getPointer());
+ return 0;
+}
+
CXXMethodDecl *
CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index 42b0205bacb..ad7aa3bee9a 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/lib/Sema/Sema.h
@@ -1784,8 +1784,7 @@ public:
/// \brief The kind of template instantiation we are performing
enum {
/// We are instantiating a template declaration. The entity is
- /// the declaration we're instantiation (e.g., a
- /// ClassTemplateSpecializationDecl).
+ /// the declaration we're instantiation (e.g., a CXXRecordDecl).
TemplateInstantiation,
/// We are instantiating a default argument for a template
@@ -1870,7 +1869,7 @@ public:
struct InstantiatingTemplate {
/// \brief Note that we are instantiating a class template.
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
- ClassTemplateSpecializationDecl *Entity,
+ CXXRecordDecl *Entity,
SourceRange InstantiationRange = SourceRange());
/// \brief Note that we are instantiating a default argument in a
@@ -1915,8 +1914,17 @@ public:
unsigned NumTemplateArgs);
bool
- InstantiateBaseSpecifiers(ClassTemplateSpecializationDecl *ClassTemplateSpec,
- ClassTemplateDecl *ClassTemplate);
+ InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation,
+ CXXRecordDecl *Pattern,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
+
+ bool
+ InstantiateClass(SourceLocation PointOfInstantiation,
+ CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
+
bool
InstantiateClassTemplateSpecialization(
ClassTemplateSpecializationDecl *ClassTemplateSpec,
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index fd89507645a..cc1a5b32a77 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -3392,11 +3392,12 @@ void Sema::ActOnTagStartDefinition(Scope *S, DeclTy *TagD) {
// class itself; this is known as the injected-class-name. For
// purposes of access checking, the injected-class-name is treated
// as if it were a public member name.
- RecordDecl *InjectedClassName
+ CXXRecordDecl *InjectedClassName
= CXXRecordDecl::Create(Context, Record->getTagKind(),
CurContext, Record->getLocation(),
Record->getIdentifier(), Record);
InjectedClassName->setImplicit();
+ InjectedClassName->setAccess(AS_public);
PushOnScopeChains(InjectedClassName, S);
assert(InjectedClassName->isInjectedClassName() &&
"Broken injected-class-name");
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 4d271a38309..60423f9f472 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -26,7 +26,7 @@ using namespace clang;
Sema::InstantiatingTemplate::
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
- ClassTemplateSpecializationDecl *Entity,
+ CXXRecordDecl *Entity,
SourceRange InstantiationRange)
: SemaRef(SemaRef) {
@@ -100,11 +100,13 @@ void Sema::PrintInstantiationStack() {
++Active) {
switch (Active->Kind) {
case ActiveTemplateInstantiation::TemplateInstantiation: {
- ClassTemplateSpecializationDecl *Spec
- = cast<ClassTemplateSpecializationDecl>((Decl*)Active->Entity);
+ unsigned DiagID = diag::note_template_member_class_here;
+ CXXRecordDecl *Record = (CXXRecordDecl *)Active->Entity;
+ if (isa<ClassTemplateSpecializationDecl>(Record))
+ DiagID = diag::note_template_class_instantiation_here;
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
- diag::note_template_class_instantiation_here)
- << Context.getTypeDeclType(Spec)
+ DiagID)
+ << Context.getTypeDeclType(Record)
<< Active->InstantiationRange;
break;
}
@@ -591,14 +593,14 @@ QualType Sema::InstantiateType(QualType T,
/// attaches the instantiated base classes to the class template
/// specialization if successful.
bool
-Sema::InstantiateBaseSpecifiers(
- ClassTemplateSpecializationDecl *ClassTemplateSpec,
- ClassTemplateDecl *ClassTemplate) {
+Sema::InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation,
+ CXXRecordDecl *Pattern,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
bool Invalid = false;
llvm::SmallVector<CXXBaseSpecifier*, 8> InstantiatedBases;
- for (ClassTemplateSpecializationDecl::base_class_iterator
- Base = ClassTemplate->getTemplatedDecl()->bases_begin(),
- BaseEnd = ClassTemplate->getTemplatedDecl()->bases_end();
+ for (ClassTemplateSpecializationDecl::base_class_iterator
+ Base = Pattern->bases_begin(), BaseEnd = Pattern->bases_end();
Base != BaseEnd; ++Base) {
if (!Base->getType()->isDependentType()) {
// FIXME: Allocate via ASTContext
@@ -607,8 +609,7 @@ Sema::InstantiateBaseSpecifiers(
}
QualType BaseType = InstantiateType(Base->getType(),
- ClassTemplateSpec->getTemplateArgs(),
- ClassTemplateSpec->getNumTemplateArgs(),
+ TemplateArgs, NumTemplateArgs,
Base->getSourceRange().getBegin(),
DeclarationName());
if (BaseType.isNull()) {
@@ -617,7 +618,7 @@ Sema::InstantiateBaseSpecifiers(
}
if (CXXBaseSpecifier *InstantiatedBase
- = CheckBaseSpecifier(ClassTemplateSpec,
+ = CheckBaseSpecifier(Instantiation,
Base->getSourceRange(),
Base->isVirtual(),
Base->getAccessSpecifierAsWritten(),
@@ -630,81 +631,82 @@ Sema::InstantiateBaseSpecifiers(
}
if (!Invalid &&
- AttachBaseSpecifiers(ClassTemplateSpec, &InstantiatedBases[0],
+ AttachBaseSpecifiers(Instantiation, &InstantiatedBases[0],
InstantiatedBases.size()))
Invalid = true;
return Invalid;
}
-bool
-Sema::InstantiateClassTemplateSpecialization(
- ClassTemplateSpecializationDecl *ClassTemplateSpec,
- bool ExplicitInstantiation) {
- // Perform the actual instantiation on the canonical declaration.
- ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
- Context.getCanonicalDecl(ClassTemplateSpec));
-
- // We can only instantiate something that hasn't already been
- // instantiated or specialized. Fail without any diagnostics: our
- // caller will provide an error message.
- if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared)
- return true;
-
- // FIXME: Push this class template instantiation onto the
- // instantiation stack, checking for recursion that exceeds a
- // certain depth.
-
- // FIXME: Perform class template partial specialization to select
- // the best template.
- ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
-
- RecordDecl *Pattern = cast_or_null<RecordDecl>(
- Template->getTemplatedDecl()->getDefinition(Context));
- if (!Pattern) {
- Diag(ClassTemplateSpec->getLocation(),
- diag::err_template_implicit_instantiate_undefined)
- << Context.getTypeDeclType(ClassTemplateSpec);
- Diag(Template->getTemplatedDecl()->getLocation(),
- diag::note_template_decl_here);
+/// \brief Instantiate the definition of a class from a given pattern.
+///
+/// \param PointOfInstantiation The point of instantiation within the
+/// source code.
+///
+/// \param Instantiation is the declaration whose definition is being
+/// instantiated. This will be either a class template specialization
+/// or a member class of a class template specialization.
+///
+/// \param Pattern is the pattern from which the instantiation
+/// occurs. This will be either the declaration of a class template or
+/// the declaration of a member class of a class template.
+///
+/// \param TemplateArgs The template arguments to be substituted into
+/// the pattern.
+///
+/// \param NumTemplateArgs The number of templates arguments in
+/// TemplateArgs.
+///
+/// \returns true if an error occurred, false otherwise.
+bool
+Sema::InstantiateClass(SourceLocation PointOfInstantiation,
+ CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
+ bool Invalid = false;
+
+ CXXRecordDecl *PatternDef
+ = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
+ if (!PatternDef) {
+ if (Pattern == Instantiation->getInstantiatedFromMemberClass()) {
+ Diag(PointOfInstantiation,
+ diag::err_implicit_instantiate_member_undefined)
+ << Context.getTypeDeclType(Instantiation);
+ Diag(Pattern->getLocation(), diag::note_member_of_template_here);
+ } else {
+ Diag(PointOfInstantiation,
+ diag::err_template_implicit_instantiate_undefined)
+ << Context.getTypeDeclType(Instantiation);
+ Diag(Pattern->getLocation(), diag::note_template_decl_here);
+ }
return true;
}
+ Pattern = PatternDef;
- // Note that this is an instantiation.
- ClassTemplateSpec->setSpecializationKind(
- ExplicitInstantiation? TSK_ExplicitInstantiation
- : TSK_ImplicitInstantiation);
-
-
- bool Invalid = false;
-
- InstantiatingTemplate Inst(*this, ClassTemplateSpec->getLocation(),
- ClassTemplateSpec);
+ InstantiatingTemplate Inst(*this, Instantiation->getLocation(),
+ Instantiation);
if (Inst)
return true;
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
DeclContext *PreviousContext = CurContext;
- CurContext = ClassTemplateSpec;
+ CurContext = Instantiation;
// Start the definition of this instantiation.
- ClassTemplateSpec->startDefinition();
+ Instantiation->startDefinition();
// Instantiate the base class specifiers.
- if (InstantiateBaseSpecifiers(ClassTemplateSpec, Template))
+ if (InstantiateBaseSpecifiers(Instantiation, Pattern, TemplateArgs,
+ NumTemplateArgs))
Invalid = true;
- // FIXME: Create the injected-class-name for the
- // instantiation. Should this be a typedef or something like it?
-
llvm::SmallVector<DeclTy *, 32> Fields;
for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
MemberEnd = Pattern->decls_end();
Member != MemberEnd; ++Member) {
- Decl *NewMember = InstantiateDecl(*Member, ClassTemplateSpec,
- ClassTemplateSpec->getTemplateArgs(),
- ClassTemplateSpec->getNumTemplateArgs());
+ Decl *NewMember = InstantiateDecl(*Member, Instantiation,
+ TemplateArgs, NumTemplateArgs);
if (NewMember) {
if (NewMember->isInvalidDecl())
Invalid = true;
@@ -719,12 +721,12 @@ Sema::InstantiateClassTemplateSpecialization(
}
// Finish checking fields.
- ActOnFields(0, ClassTemplateSpec->getLocation(), ClassTemplateSpec,
+ ActOnFields(0, Instantiation->getLocation(), Instantiation,
&Fields[0], Fields.size(), SourceLocation(), SourceLocation(),
0);
// Add any implicitly-declared members that we might need.
- AddImplicitlyDeclaredMembersToClass(ClassTemplateSpec);
+ AddImplicitlyDeclaredMembersToClass(Instantiation);
// Exit the scope of this instantiation.
CurContext = PreviousContext;
@@ -732,6 +734,41 @@ Sema::InstantiateClassTemplateSpecialization(
return Invalid;
}
+bool
+Sema::InstantiateClassTemplateSpecialization(
+ ClassTemplateSpecializationDecl *ClassTemplateSpec,
+ bool ExplicitInstantiation) {
+ // Perform the actual instantiation on the canonical declaration.
+ ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
+ Context.getCanonicalDecl(ClassTemplateSpec));
+
+ // We can only instantiate something that hasn't already been
+ // instantiated or specialized. Fail without any diagnostics: our
+ // caller will provide an error message.
+ if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared)
+ return true;
+
+ // FIXME: Push this class template instantiation onto the
+ // instantiation stack, checking for recursion that exceeds a
+ // certain depth.
+
+ // FIXME: Perform class template partial specialization to select
+ // the best template.
+ ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
+
+ CXXRecordDecl *Pattern = Template->getTemplatedDecl();
+
+ // Note that this is an instantiation.
+ ClassTemplateSpec->setSpecializationKind(
+ ExplicitInstantiation? TSK_ExplicitInstantiation
+ : TSK_ImplicitInstantiation);
+
+ return InstantiateClass(ClassTemplateSpec->getLocation(),
+ ClassTemplateSpec, Pattern,
+ ClassTemplateSpec->getTemplateArgs(),
+ ClassTemplateSpec->getNumTemplateArgs());
+}
+
/// \brief Instantiate a sequence of nested-name-specifiers into a
/// scope specifier.
CXXScopeSpec
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 7995def3322..d9f6902b54e 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -46,6 +46,7 @@ namespace {
Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
Decl *VisitEnumDecl(EnumDecl *D);
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
+ Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
Decl *VisitCXXMethodDecl(CXXMethodDecl *D);
Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
@@ -223,6 +224,24 @@ Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {
return 0;
}
+Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
+ CXXRecordDecl *PrevDecl = 0;
+ if (D->isInjectedClassName())
+ PrevDecl = cast<CXXRecordDecl>(Owner);
+
+ CXXRecordDecl *Record
+ = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner,
+ D->getLocation(), D->getIdentifier(), PrevDecl);
+ Record->setImplicit(D->isImplicit());
+ Record->setAccess(D->getAccess());
+
+ if (!D->isInjectedClassName())
+ Record->setInstantiationOfMemberClass(D);
+
+ Owner->addDecl(Record);
+ return Record;
+}
+
Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
// Only handle actual methods; we'll deal with constructors,
// destructors, etc. separately.
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 196a30642b5..4b2565795a9 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1042,11 +1042,11 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
if (!T->isIncompleteType())
return false;
- // If we have a class template specialization, try to instantiate
- // it.
- if (const RecordType *Record = T->getAsRecordType())
+ // If we have a class template specialization or a class member of a
+ // class template specialization, try to instantiate it.
+ if (const RecordType *Record = T->getAsRecordType()) {
if (ClassTemplateSpecializationDecl *ClassTemplateSpec
- = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl()))
+ = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) {
if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) {
// Update the class template specialization's location to
// refer to the point of instantiation.
@@ -1055,7 +1055,22 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
return InstantiateClassTemplateSpecialization(ClassTemplateSpec,
/*ExplicitInstantiation=*/false);
}
-
+ } else if (CXXRecordDecl *Rec
+ = dyn_cast<CXXRecordDecl>(Record->getDecl())) {
+ if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) {
+ // Find the class template specialization that surrounds this
+ // member class.
+ ClassTemplateSpecializationDecl *Spec = 0;
+ for (DeclContext *Parent = Rec->getDeclContext();
+ Parent && !Spec; Parent = Parent->getParent())
+ Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent);
+ assert(Spec && "Not a member of a class template specialization?");
+ return InstantiateClass(Loc, Rec, Pattern,
+ Spec->getTemplateArgs(),
+ Spec->getNumTemplateArgs());
+ }
+ }
+ }
if (PrintType.isNull())
PrintType = T;
OpenPOWER on IntegriCloud