From 00ee7a081d09de7e46771524a95a8555c512222a Mon Sep 17 00:00:00 2001 From: David Blaikie Date: Tue, 25 Oct 2011 15:01:20 +0000 Subject: [PATCH] Support the use of decltype for specifying base types. Fixes PR11216. llvm-svn: 142926 --- clang/include/clang/Parse/Parser.h | 3 ++- clang/lib/Parse/ParseDeclCXX.cpp | 36 +++++++++++++++++++++-------- clang/test/CXX/class.derived/p1.cpp | 33 ++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 clang/test/CXX/class.derived/p1.cpp diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index d8a13e7bc451..449d83f7c15f 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1993,7 +1993,6 @@ private: //===--------------------------------------------------------------------===// // C++ 9: classes [class] and C structs/unions. - TypeResult ParseClassName(SourceLocation &EndLocation, CXXScopeSpec &SS); void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), @@ -2013,6 +2012,8 @@ private: //===--------------------------------------------------------------------===// // C++ 10: Derived classes [class.derived] + TypeResult ParseBaseTypeSpecifier(SourceLocation &EndLocation, + CXXScopeSpec &SS); void ParseBaseClause(Decl *ClassDecl); BaseResult ParseBaseSpecifier(Decl *ClassDecl); AccessSpecifier getAccessSpecifierIfPresent() const; diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 3d3d7c21cb53..9d2db2ae1c09 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -696,18 +696,23 @@ void Parser::ParseUnderlyingTypeSpecifier(DeclSpec &DS) { Diag(StartLoc, DiagID) << PrevSpec; } -/// 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, depending on whether a type name was -/// found. +/// ParseBaseTypeSpecifier - Parse a C++ base-type-specifier which is either a +/// class name or decltype-specifier. 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, depending on whether a type +/// name was found. /// +/// base-type-specifier: [C++ 10.1] +/// class-or-decltype +/// class-or-decltype: [C++ 10.1] +/// nested-name-specifier[opt] class-name +/// decltype-specifier /// class-name: [C++ 9.1] /// identifier /// simple-template-id /// -Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, - CXXScopeSpec &SS) { +Parser::TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &EndLocation, + CXXScopeSpec &SS) { // Check whether we have a template-id that names a type. if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); @@ -728,6 +733,17 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, // Fall through to produce an error below. } + if (Tok.is(tok::kw_decltype)) { + // Fake up a Declarator to use with ActOnTypeName. + DeclSpec DS(AttrFactory); + + ParseDecltypeSpecifier(DS); + EndLocation = DS.getSourceRange().getEnd(); + + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); + } + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_class_name); return true; @@ -1363,9 +1379,9 @@ void Parser::ParseBaseClause(Decl *ClassDecl) { /// base-specifier: [C++ class.derived] /// ::[opt] nested-name-specifier[opt] class-name /// 'virtual' access-specifier[opt] ::[opt] nested-name-specifier[opt] -/// class-name +/// base-type-specifier /// access-specifier 'virtual'[opt] ::[opt] nested-name-specifier[opt] -/// class-name +/// base-type-specifier Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) { bool IsVirtual = false; SourceLocation StartLoc = Tok.getLocation(); @@ -1403,7 +1419,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) { // Parse the class-name. SourceLocation EndLocation; - TypeResult BaseType = ParseClassName(EndLocation, SS); + TypeResult BaseType = ParseBaseTypeSpecifier(EndLocation, SS); if (BaseType.isInvalid()) return true; diff --git a/clang/test/CXX/class.derived/p1.cpp b/clang/test/CXX/class.derived/p1.cpp new file mode 100644 index 000000000000..98c1d354fabc --- /dev/null +++ b/clang/test/CXX/class.derived/p1.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++11 + +// base-clause: +// : base-specifier-list +// base-specifier-list: +// base-specifier ...[opt] +// base-specifier-list , base-specifier ...[opt] +// base-specifier: +// attribute-specifier-seq[opt] base-type-specifier +// attribute-specifier-seq[opt] virtual access-specifier[opt] base-type-specifier +// attribute-specifier-seq[opt] access-specifier virtual[opt] base-type-specifier +// class-or-decltype: +// nested-name-specifier[opt] class-name +// decltype-specifier +// base-type-specifier: +// class-or-decltype +// access-specifier: +// private +// protected +// public + +namespace PR11216 { + struct Base { }; + struct Derived : decltype(Base()) { }; + + int func(); + struct Derived2 : decltype(func()) { }; // expected-error {{base specifier must name a class}} + + template + struct Derived3 : decltype(T().foo()) { }; + struct Foo { Base foo(); }; + Derived3 d; +}