forked from OSchip/llvm-project
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:
parent
ae6bc8214a
commit
1d5e9f9368
|
@ -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".
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
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,22 +2366,11 @@ 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;
|
||||
}
|
||||
|
||||
if (TemplateParams->size() > 0) {
|
||||
= MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
|
||||
(TemplateParameterList**)TemplateParameterLists.get(),
|
||||
TemplateParameterLists.size());
|
||||
if (TemplateParams && TemplateParams->size() > 0) {
|
||||
isPartialSpecialization = true;
|
||||
|
||||
// C++ [temp.class.spec]p10:
|
||||
|
@ -2418,8 +2404,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue