]> granicus.if.org Git - clang/commitdiff
Correctly handle elaborated template ids. Still not handled properly for friends.
authorJohn McCall <rjmccall@apple.com>
Fri, 4 Sep 2009 01:14:41 +0000 (01:14 +0000)
committerJohn McCall <rjmccall@apple.com>
Fri, 4 Sep 2009 01:14:41 +0000 (01:14 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80977 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
include/clang/Parse/Action.h
lib/AST/Decl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaTemplate.cpp
test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp [new file with mode: 0644]

index 0fb7fc478d55237d99fb965743da74bd65964d98..1d6c9c18722bf679f2e8266a432a7a38b3b2d2e3 100644 (file)
@@ -1340,6 +1340,11 @@ public:
     }
   }
 
+  /// getTagKindForTypeSpec - Converts a type specifier (DeclSpec::TST)
+  /// into a tag kind.  It is an error to provide a type specifier
+  /// which *isn't* a tag kind here.
+  static TagKind getTagKindForTypeSpec(unsigned TypeSpec);
+
   TagKind getTagKind() const {
     return TagKind(TagDeclKind);
   }
index 31acc87cb40a8fcb4a756ef351f4295c6da274b3..370fed996618149513900625d7950bf0368e8886 100644 (file)
@@ -1591,15 +1591,17 @@ public:
   /// \param Template  A template whose specialization results in a
   /// type, e.g., a class template or template template parameter.
   /// 
-  /// \param IsSpecialization true when we are naming the class
-  /// template specialization as part of an explicit class
-  /// specialization or class template partial specialization.
+  /// \param TagSpec The tag spec that was provided as part of the
+  /// elaborated-type-specifier, or TST_unspecified if this was not
+  /// an elaborated type.
   virtual TypeResult ActOnTemplateIdType(TemplateTy Template,
                                          SourceLocation TemplateLoc,
                                          SourceLocation LAngleLoc,
                                          ASTTemplateArgsPtr TemplateArgs,
                                          SourceLocation *TemplateArgLocs,
-                                         SourceLocation RAngleLoc) {
+                                         SourceLocation RAngleLoc,
+                        DeclSpec::TST TagSpec = DeclSpec::TST_unspecified,
+                        SourceLocation TagLoc = SourceLocation()) {
     return TypeResult();
   };
 
index fc19e61a0997deddea59088880238bc0536c2d7a..41ba1f1df9006040ad753e083671a1301be72d08 100644 (file)
@@ -22,6 +22,8 @@
 #include "clang/AST/PrettyPrinter.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/IdentifierTable.h"
+#include "clang/Parse/DeclSpec.h"
+#include "llvm/Support/ErrorHandling.h"
 #include <vector>
 
 using namespace clang;
@@ -708,6 +710,16 @@ TagDecl* TagDecl::getDefinition(ASTContext& C) const {
   return 0;
 }
 
+TagDecl::TagKind TagDecl::getTagKindForTypeSpec(unsigned TypeSpec) {
+  switch (TypeSpec) {
+  default: llvm::llvm_unreachable("unexpected type specifier");
+  case DeclSpec::TST_struct: return TK_struct;
+  case DeclSpec::TST_class: return TK_class;
+  case DeclSpec::TST_union: return TK_union;
+  case DeclSpec::TST_enum: return TK_enum;
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // RecordDecl Implementation
 //===----------------------------------------------------------------------===//
index f50147c599a9d5444dd006b84b9e37759ebc5cf7..59359530e3963f0037b13598b745e52ac1608462 100644 (file)
@@ -606,7 +606,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
   // to turn that template-id into a type.
 
   bool Owned = false;
-  if (TemplateId && TUK != Action::TUK_Reference && TUK != Action::TUK_Friend) {
+  if (TemplateId) {
     // Explicit specialization, class template partial specialization,
     // or explicit instantiation.
     ASTTemplateArgsPtr TemplateArgsPtr(Actions, 
@@ -629,6 +629,31 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
                                       TemplateId->getTemplateArgLocations(),
                                              TemplateId->RAngleLoc, 
                                              Attr);
+    } else if (TUK == Action::TUK_Reference || TUK == Action::TUK_Friend) {
+      Action::TypeResult TypeResult =
+        Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
+                                    TemplateId->TemplateNameLoc,
+                                    TemplateId->LAngleLoc,
+                                    TemplateArgsPtr,
+                                    TemplateId->getTemplateArgLocations(),
+                                    TemplateId->RAngleLoc,
+                                    TagType, StartLoc);
+
+      TemplateId->Destroy();
+
+      if (TypeResult.isInvalid()) {
+        DS.SetTypeSpecError();
+        return;
+      }
+  
+      const char *PrevSpec = 0;
+      unsigned DiagID;
+      if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, PrevSpec,
+                             DiagID, TypeResult.get()))
+        Diag(StartLoc, DiagID) << PrevSpec;
+
+      return;
+      
     } else {
       // This is an explicit specialization or a class template
       // partial specialization.
index 746c28af6201729dbe724f37944020c91134484d..f1e4968fd2d104a63a9ca53a7f397ada33eb4b93 100644 (file)
@@ -2396,7 +2396,9 @@ public:
                       SourceLocation LAngleLoc,
                       ASTTemplateArgsPtr TemplateArgs,
                       SourceLocation *TemplateArgLocs,
-                      SourceLocation RAngleLoc);
+                      SourceLocation RAngleLoc,
+                      DeclSpec::TST TagSpec,
+                      SourceLocation TagLoc);
   
   OwningExprResult BuildTemplateIdExpr(TemplateName Template,
                                        SourceLocation TemplateNameLoc,
index abf95283cdcf9397f1f7b1c6c7faeb14255a7855..e929b5f0d6d05a058a269b9c0a3f8c9627635644 100644 (file)
@@ -3966,14 +3966,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
          "Nameless record must be a definition!");
 
   OwnedDecl = false;
-  TagDecl::TagKind Kind;
-  switch (TagSpec) {
-  default: assert(0 && "Unknown tag type!");
-  case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break;
-  case DeclSpec::TST_union:  Kind = TagDecl::TK_union; break;
-  case DeclSpec::TST_class:  Kind = TagDecl::TK_class; break;
-  case DeclSpec::TST_enum:   Kind = TagDecl::TK_enum; break;
-  }
+  TagDecl::TagKind Kind = TagDecl::getTagKindForTypeSpec(TagSpec);
   
   if (TUK != TUK_Reference) {
     if (TemplateParameterList *TemplateParams
index 119e17f814d017623f753837474361e548e1e805..8eaa9fb39750612d73a26448adf5dbf77639ba89 100644 (file)
@@ -1121,7 +1121,9 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc,
                           SourceLocation LAngleLoc, 
                           ASTTemplateArgsPtr TemplateArgsIn,
                           SourceLocation *TemplateArgLocs,
-                          SourceLocation RAngleLoc) {
+                          SourceLocation RAngleLoc,
+                          DeclSpec::TST TagSpec,
+                          SourceLocation TagLoc) {
   TemplateName Template = TemplateD.getAsVal<TemplateName>();
 
   // Translate the parser's template argument list in our AST format.
@@ -1137,6 +1139,25 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc,
   if (Result.isNull())
     return true;
 
+  // If we were given a tag specifier, verify it.
+  if (TagSpec != DeclSpec::TST_unspecified) {
+    TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec);
+
+    if (const RecordType *T = Result->getAs<RecordType>()) {
+      RecordDecl *D = T->getDecl();
+
+      IdentifierInfo *Id = D->getIdentifier();
+      assert(Id && "templated class must have an identifier");
+
+      if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) {
+        Diag(TagLoc, diag::err_use_with_wrong_tag)
+          << Id
+          << CodeModificationHint::CreateReplacement(SourceRange(TagLoc),
+                                                     D->getKindName());
+      }
+    }
+  }
+
   return Result.getAsOpaquePtr();
 }
 
@@ -2497,6 +2518,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
                                        SourceLocation RAngleLoc,
                                        AttributeList *Attr,
                                MultiTemplateParamsArg TemplateParameterLists) {
+  assert(TUK == TUK_Declaration || TUK == TUK_Definition);
+
   // Find the class template we're specializing
   TemplateName Name = TemplateD.getAsVal<TemplateName>();
   ClassTemplateDecl *ClassTemplate 
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp b/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp
new file mode 100644 (file)
index 0000000..4dc1cc7
--- /dev/null
@@ -0,0 +1,18 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// elaborated-type-specifier:
+//   class-key '::'? nested-name-specifier? 'template'? simple-template-id
+// Tests that this form is accepted by the compiler but does not follow
+// the elaborated lookup rules of [basic.lookup.elab].
+
+template <typename> class Ident {};
+
+namespace A {
+  template <typename> void Ident();
+
+  class Ident<int> AIdent; // expected-error {{refers to a function template}}
+  class ::Ident<int> AnotherIdent;
+}
+
+class Ident<int> GlobalIdent;
+union Ident<int> GlobalIdent; // expected-error {{ tag type that does not match }}