Implement out-of-line definitions of nested class templates. Most of

the logic is there for out-of-line definitions with multiple levels of
nested templates, but this is still a work-in-progress: we're having
trouble determining when we should look into a dependent
nested-name-specifier. 

llvm-svn: 80003
This commit is contained in:
Douglas Gregor 2009-08-25 17:23:04 +00:00
parent ae6bc8214a
commit 1d5e9f9368
4 changed files with 120 additions and 99 deletions

View File

@ -2258,7 +2258,7 @@ public:
SourceLocation KWLoc, const CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
MultiTemplateParamsArg TemplateParameterLists,
TemplateParameterList *TemplateParams,
AccessSpecifier AS);
QualType CheckTemplateIdType(TemplateName Template,
@ -2378,8 +2378,7 @@ public:
SourceLocation TemplateArgLoc
= SourceLocation());
bool CheckTemplateDeclScope(Scope *S,
MultiTemplateParamsArg &TemplateParameterLists);
bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams);
/// \brief Called when the parser has parsed a C++ typename
/// specifier, e.g., "typename T::type".

View File

@ -2106,11 +2106,6 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
}
// Check that we can declare a template here.
if (TemplateParamLists.size() &&
CheckTemplateDeclScope(S, TemplateParamLists))
return 0;
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
if (TemplateParameterList *TemplateParams
@ -2391,11 +2386,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
D.setInvalidType();
}
// Check that we can declare a template here.
if (TemplateParamLists.size() &&
CheckTemplateDeclScope(S, TemplateParamLists))
return 0;
bool isVirtualOkay = false;
FunctionDecl *NewFD;
if (isFriend) {
@ -2515,6 +2505,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
TemplateParamLists.size())) {
if (TemplateParams->size() > 0) {
// This is a function template
// Check that we can declare a template here.
if (CheckTemplateDeclScope(S, TemplateParams))
return 0;
FunctionTemplate = FunctionTemplateDecl::Create(Context, CurContext,
NewFD->getLocation(),
Name, TemplateParams,
@ -3960,8 +3955,9 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
OwnedDecl = false;
DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc,
SS, Name, NameLoc, Attr,
move(TemplateParameterLists),
TemplateParams,
AS);
TemplateParameterLists.release();
return Result.get();
} else {
// FIXME: diagnose the extraneous 'template<>', once we recover

View File

@ -444,14 +444,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
SourceLocation KWLoc, const CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
MultiTemplateParamsArg TemplateParameterLists,
TemplateParameterList *TemplateParams,
AccessSpecifier AS) {
assert(TemplateParameterLists.size() > 0 && "No template parameter lists?");
assert(TemplateParams && TemplateParams->size() > 0 &&
"No template parameters");
assert(TUK != TUK_Reference && "Can only declare or define class templates");
bool Invalid = false;
// Check that we can declare a template here.
if (CheckTemplateDeclScope(S, TemplateParameterLists))
if (CheckTemplateDeclScope(S, TemplateParams))
return true;
TagDecl::TagKind Kind;
@ -469,27 +470,30 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
// Find any previous declaration with this name.
LookupResult Previous = LookupParsedName(S, &SS, Name, LookupOrdinaryName,
true);
DeclContext *SemanticContext;
LookupResult Previous;
if (SS.isNotEmpty() && !SS.isInvalid()) {
SemanticContext = computeDeclContext(SS, true);
if (!SemanticContext) {
// FIXME: Produce a reasonable diagnostic here
return true;
}
Previous = LookupQualifiedName(SemanticContext, Name, LookupOrdinaryName,
true);
} else {
SemanticContext = CurContext;
Previous = LookupName(S, Name, LookupOrdinaryName, true);
}
assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?");
NamedDecl *PrevDecl = 0;
if (Previous.begin() != Previous.end())
PrevDecl = *Previous.begin();
if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S))
if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S))
PrevDecl = 0;
DeclContext *SemanticContext = CurContext;
if (SS.isNotEmpty() && !SS.isInvalid()) {
SemanticContext = computeDeclContext(SS);
// FIXME: need to match up several levels of template parameter lists here.
}
// FIXME: member templates!
TemplateParameterList *TemplateParams
= static_cast<TemplateParameterList *>(*TemplateParameterLists.release());
// If there is a previous declaration with the same name, check
// whether this is a valid redeclaration.
ClassTemplateDecl *PrevClassTemplate
@ -2106,28 +2110,20 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New,
/// If the template declaration is valid in this scope, returns
/// false. Otherwise, issues a diagnostic and returns true.
bool
Sema::CheckTemplateDeclScope(Scope *S,
MultiTemplateParamsArg &TemplateParameterLists) {
assert(TemplateParameterLists.size() > 0 && "Not a template");
Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
// Find the nearest enclosing declaration scope.
while ((S->getFlags() & Scope::DeclScope) == 0 ||
(S->getFlags() & Scope::TemplateParamScope) != 0)
S = S->getParent();
TemplateParameterList *TemplateParams =
static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
SourceLocation TemplateLoc = TemplateParams->getTemplateLoc();
SourceRange TemplateRange
= SourceRange(TemplateLoc, TemplateParams->getRAngleLoc());
// C++ [temp]p2:
// A template-declaration can appear only as a namespace scope or
// class scope declaration.
DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
if (Ctx && isa<LinkageSpecDecl>(Ctx) &&
cast<LinkageSpecDecl>(Ctx)->getLanguage() != LinkageSpecDecl::lang_cxx)
return Diag(TemplateLoc, diag::err_template_linkage) << TemplateRange;
return Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage)
<< TemplateParams->getSourceRange();
while (Ctx && isa<LinkageSpecDecl>(Ctx))
Ctx = Ctx->getParent();
@ -2135,8 +2131,9 @@ Sema::CheckTemplateDeclScope(Scope *S,
if (Ctx && (Ctx->isFileContext() || Ctx->isRecord()))
return false;
return Diag(TemplateLoc, diag::err_template_outside_namespace_or_class_scope)
<< TemplateRange;
return Diag(TemplateParams->getTemplateLoc(),
diag::err_template_outside_namespace_or_class_scope)
<< TemplateParams->getSourceRange();
}
/// \brief Check whether a class template specialization or explicit
@ -2369,57 +2366,47 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// Check the validity of the template headers that introduce this
// template.
// FIXME: Once we have member templates, we'll need to check
// C++ [temp.expl.spec]p17-18, where we could have multiple levels of
// template<> headers.
if (TemplateParameterLists.size() == 0)
Diag(KWLoc, diag::err_template_spec_needs_header)
<< CodeModificationHint::CreateInsertion(KWLoc, "template<> ");
else {
TemplateParameterList *TemplateParams
= static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
if (TemplateParameterLists.size() > 1) {
Diag(TemplateParams->getTemplateLoc(),
diag::err_template_spec_extra_headers);
return true;
}
TemplateParameterList *TemplateParams
= MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
(TemplateParameterList**)TemplateParameterLists.get(),
TemplateParameterLists.size());
if (TemplateParams && TemplateParams->size() > 0) {
isPartialSpecialization = true;
if (TemplateParams->size() > 0) {
isPartialSpecialization = true;
// C++ [temp.class.spec]p10:
// The template parameter list of a specialization shall not
// contain default template argument values.
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
Decl *Param = TemplateParams->getParam(I);
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
if (TTP->hasDefaultArgument()) {
Diag(TTP->getDefaultArgumentLoc(),
diag::err_default_arg_in_partial_spec);
TTP->setDefaultArgument(QualType(), SourceLocation(), false);
}
} else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
if (Expr *DefArg = NTTP->getDefaultArgument()) {
Diag(NTTP->getDefaultArgumentLoc(),
diag::err_default_arg_in_partial_spec)
<< DefArg->getSourceRange();
NTTP->setDefaultArgument(0);
DefArg->Destroy(Context);
}
} else {
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(Param);
if (Expr *DefArg = TTP->getDefaultArgument()) {
Diag(TTP->getDefaultArgumentLoc(),
diag::err_default_arg_in_partial_spec)
<< DefArg->getSourceRange();
TTP->setDefaultArgument(0);
DefArg->Destroy(Context);
}
// C++ [temp.class.spec]p10:
// The template parameter list of a specialization shall not
// contain default template argument values.
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
Decl *Param = TemplateParams->getParam(I);
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
if (TTP->hasDefaultArgument()) {
Diag(TTP->getDefaultArgumentLoc(),
diag::err_default_arg_in_partial_spec);
TTP->setDefaultArgument(QualType(), SourceLocation(), false);
}
} else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
if (Expr *DefArg = NTTP->getDefaultArgument()) {
Diag(NTTP->getDefaultArgumentLoc(),
diag::err_default_arg_in_partial_spec)
<< DefArg->getSourceRange();
NTTP->setDefaultArgument(0);
DefArg->Destroy(Context);
}
} else {
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(Param);
if (Expr *DefArg = TTP->getDefaultArgument()) {
Diag(TTP->getDefaultArgumentLoc(),
diag::err_default_arg_in_partial_spec)
<< DefArg->getSourceRange();
TTP->setDefaultArgument(0);
DefArg->Destroy(Context);
}
}
}
}
} else if (!TemplateParams)
Diag(KWLoc, diag::err_template_spec_needs_header)
<< CodeModificationHint::CreateInsertion(KWLoc, "template<> ");
// Check that the specialization uses the same tag kind as the
// original template.
@ -2482,7 +2469,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
ClassTemplate->getIdentifier(),
TemplateNameLoc,
Attr,
move(TemplateParameterLists),
TemplateParams,
AS_none);
}

View File

@ -15,16 +15,55 @@ int i;
S::A<int>::Nested::type *ip = &i;
template<typename T>
struct X0 {
template<typename U> void f0(T, U);
struct Outer {
template<typename U>
class Inner0;
template<typename U>
struct Inner0 {
void f1(T, U);
class Inner1 {
struct ReallyInner;
T foo(U);
template<typename V> T bar(V);
};
};
template<typename X> template<typename Y> void X0<X>::f0(X, Y) { }
template<typename X>
template<typename Y>
class Outer<X>::Inner0 {
public:
void f(X, Y);
};
// FIXME:
// template<typename X> template<typename Y> void X0<X>::Inner0<Y>::f1(X, Y) { }
#if 0
// FIXME: These don't parse properly because we can't handle the template-name
// "Inner0" or "Inner1" after the dependent type Outer<X>.
template<typename X>
template<typename Y>
void Outer<X>::Inner0<Y>::f(X, Y) {
}
template<typename X>
template<typename Y>
struct Outer<X>::Inner1<Y>::ReallyInner {
void g(X, Y);
};
template<typename X>
template<typename Y>
void Outer<X>::Inner1<Y>::ReallyInner::g(X, Y) {
}
template<typename X>
template<typename Y>
X Outer<X>::Inner1<Y>::foo(Y) {
return X();
}
template<typename X>
template<typename Y>
template<typename Z>
X Outer<X>::Inner1<Y>::bar(Z) {
return X();
}
#endif