diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index df62573e8cda..76d069fd8a23 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -733,10 +733,11 @@ def note_template_param_prev_default_arg : Note< "previous default template argument defined here">; def err_template_param_default_arg_missing : Error< "template parameter missing a default argument">; - + def err_template_variable : Error<"variable %0 declared as a template">; def err_template_variable_noparams : Error< "extraneous 'template<>' in declaration of variable %0">; + // C++ Template Argument Lists def err_template_arg_list_different_arity : Error< "%select{too few|too many}0 template arguments for " diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 23c5428ef687..92f38ede8955 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -422,6 +422,18 @@ public: bool &OwnedDecl) { // TagType is an instance of DeclSpec::TST, indicating what kind of tag this // is (struct/union/enum/class). + return ActOnTag(S, TagSpec, TK, KWLoc, SS, Name, NameLoc, Attr, AS, + MultiTemplateParamsArg(*this, 0, 0), OwnedDecl); + } + + virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, + SourceLocation KWLoc, const CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, AccessSpecifier AS, + MultiTemplateParamsArg TemplateParameterLists, + bool &OwnedDecl) { + // TagType is an instance of DeclSpec::TST, indicating what kind of tag this + // is (struct/union/enum/class). return DeclPtrTy(); } diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 930d58dd2624..f28ffe350940 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -673,15 +673,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateParams? TemplateParams->size() : 0)); } TemplateId->Destroy(); - } else if (TemplateParams && TK != Action::TK_Reference) { - // Class template declaration or definition. - TagOrTempResult = Actions.ActOnClassTemplate(CurScope, TagType, TK, - StartLoc, SS, Name, NameLoc, - Attr, - Action::MultiTemplateParamsArg(Actions, - &(*TemplateParams)[0], - TemplateParams->size()), - AS); } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TK == Action::TK_Declaration) { // Explicit instantiation of a member of a class template @@ -702,7 +693,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Declaration or definition of a class type TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS, - Name, NameLoc, Attr, AS, Owned); + Name, NameLoc, Attr, AS, + Action::MultiTemplateParamsArg(Actions, + TemplateParams? &(*TemplateParams)[0] : 0, + TemplateParams? TemplateParams->size() : 0), + Owned); } // Parse the optional base clause (C++ only). diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 57a09fbc737f..df7c22cf2652 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -96,9 +96,15 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, // Parse the '<' template-parameter-list '>' SourceLocation LAngleLoc, RAngleLoc; TemplateParameterList TemplateParams; - ParseTemplateParameters(ParamLists.size(), TemplateParams, LAngleLoc, - RAngleLoc); - + if (ParseTemplateParameters(ParamLists.size(), TemplateParams, LAngleLoc, + RAngleLoc)) { + // Skip until the semi-colon or a }. + SkipUntil(tok::r_brace, true, true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return DeclPtrTy(); + } + if (!TemplateParams.empty()) isSpecialiation = false; @@ -219,6 +225,8 @@ Parser::ParseSingleDeclarationAfterTemplate( /// The template parameter we parse will be added to this list. LAngleLoc and /// RAngleLoc will receive the positions of the '<' and '>', respectively, /// that enclose this template parameter list. +/// +/// \returns true if an error occurred, false otherwise. bool Parser::ParseTemplateParameters(unsigned Depth, TemplateParameterList &TemplateParams, SourceLocation &LAngleLoc, @@ -226,7 +234,7 @@ bool Parser::ParseTemplateParameters(unsigned Depth, // Get the template parameter list. if(!Tok.is(tok::less)) { Diag(Tok.getLocation(), diag::err_expected_less_after) << "template"; - return false; + return true; } LAngleLoc = ConsumeToken(); @@ -236,11 +244,11 @@ bool Parser::ParseTemplateParameters(unsigned Depth, else if(ParseTemplateParameterList(Depth, TemplateParams)) { if(!Tok.is(tok::greater)) { Diag(Tok.getLocation(), diag::err_expected_greater); - return false; + return true; } RAngleLoc = ConsumeToken(); } - return true; + return false; } /// ParseTemplateParameterList - Parse a template parameter list. If @@ -392,8 +400,8 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { SourceLocation LAngleLoc, RAngleLoc; { ParseScope TemplateParmScope(this, Scope::TemplateParamScope); - if(!ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc, - RAngleLoc)) { + if(ParseTemplateParameters(Depth + 1, TemplateParams, LAngleLoc, + RAngleLoc)) { return DeclPtrTy(); } } diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 7daf3f90a86e..78d64b53c099 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -522,6 +522,7 @@ public: SourceLocation KWLoc, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, + MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl); virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart, diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index cf73725e7f36..be1a1103b3d4 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -213,7 +213,7 @@ bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) { if (!SS.isSet() || SS.isInvalid()) return false; - DeclContext *DC = computeDeclContext(SS); + DeclContext *DC = computeDeclContext(SS, true); if (TagDecl *Tag = dyn_cast(DC)) { // If we're currently defining this type, then lookup into the // type is okay: don't complain that it isn't complete yet. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 2e280f58cb5b..d9c1224b435f 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1866,14 +1866,14 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, } else { // There is an extraneous 'template<>' for this variable. Complain // about it, but allow the declaration of the variable. - Diag(TemplateParams->getTemplateLoc(), diag::err_template_variable) + Diag(TemplateParams->getTemplateLoc(), + diag::err_template_variable_noparams) << II << SourceRange(TemplateParams->getTemplateLoc(), TemplateParams->getRAngleLoc()); } } - // The variable can not NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), II, R, SC, // FIXME: Move to DeclGroup... @@ -3522,6 +3522,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, SourceLocation KWLoc, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, + MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl) { // If this is not a definition, it must have a name. assert((Name != 0 || TK == TK_Definition) && @@ -3537,6 +3538,28 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, case DeclSpec::TST_enum: Kind = TagDecl::TK_enum; break; } + if (TK != TK_Reference) { + if (TemplateParameterList *TemplateParams + = MatchTemplateParametersToScopeSpecifier(KWLoc, SS, + (TemplateParameterList**)TemplateParameterLists.get(), + TemplateParameterLists.size())) { + if (TemplateParams->size() > 0) { + // This is a declaration or definition of a class template (which may + // be a member of another template). + OwnedDecl = false; + DeclResult Result = ActOnClassTemplate(S, TagSpec, TK, KWLoc, + SS, Name, NameLoc, Attr, + move(TemplateParameterLists), + AS); + return Result.get(); + } else { + // FIXME: diagnose the extraneous 'template<>', once we recover + // slightly better in ParseTemplate.cpp from bogus template + // parameters. + } + } + } + DeclContext *SearchDC = CurContext; DeclContext *DC = CurContext; NamedDecl *PrevDecl = 0; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 5f772bc22c06..981b8508c565 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2895,7 +2895,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, bool Owned = false; DeclPtrTy TagD = ActOnTag(S, TagSpec, Action::TK_Reference, - KWLoc, SS, Name, NameLoc, Attr, AS_none, Owned); + KWLoc, SS, Name, NameLoc, Attr, AS_none, + MultiTemplateParamsArg(*this, 0, 0), Owned); if (!TagD) return true; diff --git a/clang/test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp b/clang/test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp new file mode 100644 index 000000000000..9bafacc00a7b --- /dev/null +++ b/clang/test/CXX/temp/temp.decls/temp.class/temp.mem.class/p1.cpp @@ -0,0 +1,27 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template +struct X0 { + struct Inner; +}; + +template +struct X0::Inner { + T x; + U y; + + void f() { x = y; } // expected-error{{incompatible}} +}; + + +void test(int i, float f) { + X0::Inner inner; + inner.x = 5; + inner.y = 3.4; + inner.f(); + + X0::Inner inner2; + inner2.x = &i; + inner2.y = &f; + inner2.f(); // expected-note{{instantiation}} +} \ No newline at end of file diff --git a/clang/test/Parser/cxx-template-decl.cpp b/clang/test/Parser/cxx-template-decl.cpp index b7117cd8d620..5f49fb15d7cf 100644 --- a/clang/test/Parser/cxx-template-decl.cpp +++ b/clang/test/Parser/cxx-template-decl.cpp @@ -3,12 +3,8 @@ // Errors export class foo { }; // expected-error {{expected template}} template x; // expected-error {{C++ requires a type specifier for all declarations}} -export template x; // expected-error {{expected '<' after 'template'}} \ - // expected-note {{exported templates are unsupported}} \ -// expected-error {{C++ requires a type specifier for all declarations}} \ -// expected-error {{declared as a template}} -// See Sema::ParsedFreeStandingDeclSpec about the double diagnostic. This is -// because ParseNonTypeTemplateParameter starts parsing a DeclSpec. +export template x; // expected-error {{expected '<' after 'template'}} +export template class x0; // expected-note {{exported templates are unsupported}} template < ; // expected-error {{parse error}} expected-error {{declaration does not declare anything}} template