Implementing parsing of template-ids as class-names, so that we can

derive from a class template specialization, e.g.,

  class B : public A<int> { };

llvm-svn: 65488
This commit is contained in:
Douglas Gregor 2009-02-25 23:52:28 +00:00
parent b750d928ce
commit d54dfb8718
4 changed files with 53 additions and 11 deletions

View File

@ -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,

View File

@ -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);

View File

@ -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<TemplateIdAnnotation *>(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.

View File

@ -0,0 +1,23 @@
// RUN: clang -fsyntax-only -verify %s
namespace N {
template<typename T> class A;
template<> class A<int> { };
class B : public A<int> { };
}
class C1 : public N::A<int> { };
class C2 : public N::A<float> { }; // expected-error{{base class has incomplete type}} \
// FIXME: expected-note{{forward declaration of 'class A'}}
struct D1 {
operator N::A<int>();
};
namespace N {
struct D2 {
operator A<int>();
};
}