]> granicus.if.org Git - clang/commitdiff
Support the use of decltype for specifying base types. Fixes PR11216.
authorDavid Blaikie <dblaikie@gmail.com>
Tue, 25 Oct 2011 15:01:20 +0000 (15:01 +0000)
committerDavid Blaikie <dblaikie@gmail.com>
Tue, 25 Oct 2011 15:01:20 +0000 (15:01 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142926 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Parse/Parser.h
lib/Parse/ParseDeclCXX.cpp
test/CXX/class.derived/p1.cpp [new file with mode: 0644]

index d8a13e7bc45176287f22aa4d58f763c265cf3e85..449d83f7c15ff413eb9ba6c6b101765308c832ad 100644 (file)
@@ -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;
index 3d3d7c21cb53d96d0807049d1d357081603e9312..9d2db2ae1c09de91ebc2bdba9fc915930b8275e5 100644 (file)
@@ -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/test/CXX/class.derived/p1.cpp b/test/CXX/class.derived/p1.cpp
new file mode 100644 (file)
index 0000000..98c1d35
--- /dev/null
@@ -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<typename T>
+  struct Derived3 : decltype(T().foo()) { };
+  struct Foo { Base foo(); };
+  Derived3<Foo> d;
+}