diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 363f3ade7901..85f287e688bf 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -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". diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 99c1338fbae2..ee6238c56c4e 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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 diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 7b29c9432a97..bb6fe9228312 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -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(*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(*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(S->getEntity()); if (Ctx && isa(Ctx) && cast(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(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(*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(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(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(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(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(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(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); } diff --git a/clang/test/SemaTemplate/nested-template.cpp b/clang/test/SemaTemplate/nested-template.cpp index 9562bcb51ef7..05ab3e9c1bf9 100644 --- a/clang/test/SemaTemplate/nested-template.cpp +++ b/clang/test/SemaTemplate/nested-template.cpp @@ -15,16 +15,55 @@ int i; S::A::Nested::type *ip = &i; template -struct X0 { - template void f0(T, U); +struct Outer { + template + class Inner0; template - struct Inner0 { - void f1(T, U); + class Inner1 { + struct ReallyInner; + + T foo(U); + template T bar(V); }; }; -template template void X0::f0(X, Y) { } +template +template +class Outer::Inner0 { +public: + void f(X, Y); +}; -// FIXME: -// template template void X0::Inner0::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. +template +template +void Outer::Inner0::f(X, Y) { +} + +template +template +struct Outer::Inner1::ReallyInner { + void g(X, Y); +}; + +template +template +void Outer::Inner1::ReallyInner::g(X, Y) { +} + +template +template +X Outer::Inner1::foo(Y) { + return X(); +} + +template +template +template +X Outer::Inner1::bar(Z) { + return X(); +} +#endif \ No newline at end of file