From: Douglas Gregor Date: Wed, 25 Feb 2009 23:52:28 +0000 (+0000) Subject: Implementing parsing of template-ids as class-names, so that we can X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7f43d6764797ab21216421aeb00f4ec314d503d1;p=clang Implementing parsing of template-ids as class-names, so that we can derive from a class template specialization, e.g., class B : public A { }; git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65488 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 9ef23d4865..1e3ea317da 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -968,7 +968,8 @@ private: //===--------------------------------------------------------------------===// // C++ 9: classes [class] and C structs/unions. - TypeTy *ParseClassName(const CXXScopeSpec *SS = 0); + TypeTy *ParseClassName(SourceLocation &EndLocation, + const CXXScopeSpec *SS = 0); void ParseClassSpecifier(DeclSpec &DS, TemplateParameterLists *TemplateParams = 0); void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index bdd352f341..b961bc2dc0 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1822,7 +1822,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (Tok.is(tok::identifier)) { // FIXME: Inaccurate. SourceLocation NameLoc = Tok.getLocation(); - if (TypeTy *Type = ParseClassName()) { + SourceLocation EndLoc; + if (TypeTy *Type = ParseClassName(EndLoc)) { D.setDestructor(Type, TildeLoc, NameLoc); } else { D.SetIdentifier(0, TildeLoc); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 3ef3f93fdf..9f704d2ea8 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -216,16 +216,33 @@ Parser::DeclTy *Parser::ParseUsingDeclaration(unsigned Context, /// ParseClassName - Parse a C++ class-name, which names a class. Note /// that we only check that the result names a type; semantic analysis /// will need to verify that the type names a class. The result is -/// either a type or NULL, dependending on whether a type name was +/// either a type or NULL, depending on whether a type name was /// found. /// /// class-name: [C++ 9.1] /// identifier -/// template-id [TODO] +/// simple-template-id /// -Parser::TypeTy *Parser::ParseClassName(const CXXScopeSpec *SS) { - // Parse the class-name. - // FIXME: Alternatively, parse a simple-template-id. +Parser::TypeTy *Parser::ParseClassName(SourceLocation &EndLocation, + const CXXScopeSpec *SS) { + // Check whether we have a template-id that names a type. + if (Tok.is(tok::annot_template_id)) { + TemplateIdAnnotation *TemplateId + = static_cast(Tok.getAnnotationValue()); + if (TemplateId->Kind == TNK_Class_template) { + if (AnnotateTemplateIdTokenAsType(SS)) + return 0; + + assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); + TypeTy *Type = Tok.getAnnotationValue(); + EndLocation = Tok.getAnnotationEndLoc(); + ConsumeToken(); + return Type; + } + + // Fall through to produce an error below. + } + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_class_name); return 0; @@ -240,8 +257,7 @@ Parser::TypeTy *Parser::ParseClassName(const CXXScopeSpec *SS) { } // Consume the identifier. - ConsumeToken(); - + EndLocation = ConsumeToken(); return Type; } @@ -510,12 +526,13 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclTy *ClassDecl) SourceLocation BaseLoc = Tok.getLocation(); // Parse the class-name. - TypeTy *BaseType = ParseClassName(&SS); + SourceLocation EndLocation; + TypeTy *BaseType = ParseClassName(EndLocation, &SS); if (!BaseType) return true; // Find the complete source range for the base-specifier. - SourceRange Range(StartLoc, BaseLoc); + SourceRange Range(StartLoc, EndLocation); // Notify semantic analysis that we have parsed a complete // base-specifier. diff --git a/test/SemaTemplate/class-template-id-2.cpp b/test/SemaTemplate/class-template-id-2.cpp new file mode 100644 index 0000000000..dee4735de9 --- /dev/null +++ b/test/SemaTemplate/class-template-id-2.cpp @@ -0,0 +1,23 @@ +// RUN: clang -fsyntax-only -verify %s +namespace N { + template class A; + + template<> class A { }; + + class B : public A { }; +} + +class C1 : public N::A { }; + +class C2 : public N::A { }; // expected-error{{base class has incomplete type}} \ + // FIXME: expected-note{{forward declaration of 'class A'}} + +struct D1 { + operator N::A(); +}; + +namespace N { + struct D2 { + operator A(); + }; +}