]> granicus.if.org Git - clang/commitdiff
Introduce support for finding class and enum names via ordinary name lookup in C++
authorDouglas Gregor <dgregor@apple.com>
Sun, 13 Apr 2008 21:07:44 +0000 (21:07 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sun, 13 Apr 2008 21:07:44 +0000 (21:07 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@49621 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ASTContext.h
include/clang/AST/DeclBase.h
include/clang/AST/Type.h
lib/AST/ASTContext.cpp
lib/Sema/IdentifierResolver.cpp
lib/Sema/IdentifierResolver.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaType.cpp
test/Sema/class-names.cpp [new file with mode: 0644]

index 2f669b131de4816ebf09378d23429f477ade4cda..b29c23e3f76b8539e3722bf6ac368c499265df32 100644 (file)
@@ -176,7 +176,11 @@ public:
   /// list.  isVariadic indicates whether the argument list includes '...'.
   QualType getFunctionType(QualType ResultTy, QualType *ArgArray,
                            unsigned NumArgs, bool isVariadic);
-  
+
+  /// getTypeDeclType - Return the unique reference to the type for
+  /// the specified type declaration.
+  QualType getTypeDeclType(TypeDecl *Decl);
+
   /// getTypedefType - Return the unique reference to the type for the
   /// specified typename decl.
   QualType getTypedefType(TypedefDecl *Decl);
index 058cb9223ce1858afefbbb912a394839453b453a..a5c1cb29ec87e91acbcedc593a668e1f7478d7f9 100644 (file)
@@ -80,12 +80,14 @@ public:
   };
 
   /// IdentifierNamespace - According to C99 6.2.3, there are four namespaces,
-  /// labels, tags, members and ordinary identifiers.
+  /// labels, tags, members and ordinary identifiers. These are meant
+  /// as bitmasks, so that searches in C++ can look into the "tag" namespace
+  /// during ordinary lookup.
   enum IdentifierNamespace {
-    IDNS_Label,
-    IDNS_Tag,
-    IDNS_Member,
-    IDNS_Ordinary
+    IDNS_Label = 0x1,
+    IDNS_Tag = 0x2,
+    IDNS_Member = 0x4,
+    IDNS_Ordinary = 0x8
   };
   
   /// ObjCDeclQualifier - Qualifier used on types in method declarations
index 5d36b759a3cb3d075dfd8c2341e02ff254134824..8b5ed4ce6386091a3d7c8bb93a0e2e2abec9517e 100644 (file)
@@ -994,10 +994,11 @@ public:
 
 class TagType : public Type {
   TagDecl *decl;
+
+protected:
   TagType(TagDecl *D, QualType can) : Type(Tagged, can), decl(D) {}
-  friend class ASTContext;  // ASTContext creates these.
-public:
-    
+
+public:   
   TagDecl *getDecl() const { return decl; }
   
   virtual void getAsStringInternal(std::string &InnerString) const;
@@ -1014,7 +1015,8 @@ protected:
 /// RecordType - This is a helper class that allows the use of isa/cast/dyncast
 /// to detect TagType objects of structs/unions/classes.
 class RecordType : public TagType {
-  RecordType(); // DO NOT IMPLEMENT
+  explicit RecordType(RecordDecl *D) : TagType(cast<TagDecl>(D), QualType()) { }
+  friend class ASTContext;   // ASTContext creates these.
 public:
     
   RecordDecl *getDecl() const {
@@ -1040,7 +1042,8 @@ public:
 /// EnumType - This is a helper class that allows the use of isa/cast/dyncast
 /// to detect TagType objects of enums.
 class EnumType : public TagType {
-  EnumType(); // DO NOT IMPLEMENT
+  explicit EnumType(EnumDecl *D) : TagType(cast<TagDecl>(D), QualType()) { }
+  friend class ASTContext;   // ASTContext creates these.
 public:
     
   EnumDecl *getDecl() const {
index 5af59aadd370c0f8ce7057db389a1d08c575b377..e4b48e21e44dad4064f0d65d1fdfcbfee6381d64 100644 (file)
@@ -788,6 +788,28 @@ QualType ASTContext::getFunctionType(QualType ResultTy, QualType *ArgArray,
   return QualType(FTP, 0);
 }
 
+/// getTypeDeclType - Return the unique reference to the type for the
+/// specified type declaration.
+QualType ASTContext::getTypeDeclType(TypeDecl *Decl) {
+  if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
+  
+  if (TypedefDecl *Typedef = dyn_cast_or_null<TypedefDecl>(Decl))
+    return getTypedefType(Typedef);
+  else if (ObjCInterfaceDecl *ObjCInterface 
+             = dyn_cast_or_null<ObjCInterfaceDecl>(Decl))
+    return getObjCInterfaceType(ObjCInterface);
+  else if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Decl)) {
+    Decl->TypeForDecl = new RecordType(Record);
+    Types.push_back(Decl->TypeForDecl);
+    return QualType(Decl->TypeForDecl, 0);
+  } else if (EnumDecl *Enum = dyn_cast_or_null<EnumDecl>(Decl)) {
+    Decl->TypeForDecl = new EnumType(Enum);
+    Types.push_back(Decl->TypeForDecl);
+    return QualType(Decl->TypeForDecl, 0);    
+  } else
+    assert(false && "TypeDecl without a type?");
+}
+
 /// getTypedefType - Return the unique reference to the type for the
 /// specified typename decl.
 QualType ASTContext::getTypedefType(TypedefDecl *Decl) {
@@ -913,15 +935,7 @@ QualType ASTContext::getTypeOfType(QualType tofType) {
 /// specified TagDecl (struct/union/class/enum) decl.
 QualType ASTContext::getTagDeclType(TagDecl *Decl) {
   assert (Decl);
-
-  // The decl stores the type cache.
-  if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
-  
-  TagType* T = new TagType(Decl, QualType());
-  Types.push_back(T);  
-  Decl->TypeForDecl = T;
-
-  return QualType(T, 0);
+  return getTypeDeclType(Decl);
 }
 
 /// getSizeType - Return the unique type for "size_t" (C99 7.17), the result 
index 79898e438064980a74a991a6c62b403817fa852b..037802c64042c6d35f8105cc2580dd0128538c2d 100644 (file)
@@ -15,6 +15,7 @@
 #include "IdentifierResolver.h"
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/AST/Decl.h"
+#include "clang/Parse/Scope.h"
 #include <list>
 #include <vector>
 
@@ -113,6 +114,25 @@ void IdentifierResolver::AddDecl(NamedDecl *D, Scope *S) {
   } else
     IDI = toIdDeclInfo(Ptr);
 
+  // C++ [basic.scope]p4:
+  //   -- exactly one declaration shall declare a class name or
+  //   enumeration name that is not a typedef name and the other
+  //   declarations shall all refer to the same object or
+  //   enumerator, or all refer to functions and function templates;
+  //   in this case the class name or enumeration name is hidden.
+  if (isa<TagDecl>(D)) {
+    // We are pushing the name of a tag (enum or class).
+    IdDeclInfo::ShadowedIter TopIter = IDI->shadowed_end() - 1;
+    if (S->isDeclScope(*TopIter)) {
+      // There is already a declaration with the same name in the same
+      // scope. It must be found before we find the new declaration,
+      // so swap the order on the shadowed declaration stack.
+      NamedDecl *Temp = *TopIter;
+      *TopIter = D;
+      D = Temp;
+    }
+  }
+
   IDI->PushShadowed(D);
 }
 
@@ -159,16 +179,15 @@ void IdentifierResolver::RemoveDecl(NamedDecl *D) {
 
 /// Lookup - Find the non-shadowed decl that belongs to a particular
 /// Decl::IdentifierNamespace.
-NamedDecl *IdentifierResolver::Lookup(const IdentifierInfo *II, unsigned NSI) {
+NamedDecl *IdentifierResolver::Lookup(const IdentifierInfo *II, unsigned NS) {
   assert(II && "null param passed");
-  Decl::IdentifierNamespace NS = (Decl::IdentifierNamespace)NSI;
   void *Ptr = II->getFETokenInfo<void>();
 
   if (!Ptr) return NULL;
 
   if (isDeclPtr(Ptr)) {
     NamedDecl *D = static_cast<NamedDecl*>(Ptr);
-    return (D->getIdentifierNamespace() == NS) ? D : NULL;
+    return (D->getIdentifierNamespace() & NS) ? D : NULL;
   }
 
   IdDeclInfo *IDI = toIdDeclInfo(Ptr);
@@ -178,7 +197,7 @@ NamedDecl *IdentifierResolver::Lookup(const IdentifierInfo *II, unsigned NSI) {
   for (IdDeclInfo::ShadowedIter SI = IDI->shadowed_end();
        SI != IDI->shadowed_begin(); --SI) {
     NamedDecl *D = *(SI-1);
-    if (D->getIdentifierNamespace() == NS)
+    if (D->getIdentifierNamespace() & NS)
       return D;
   }
 
index bdaab694fe10d2d1e871ac4408489a35c7d5a8d6..abe568d60279320667455727ad8aecb4d8209983 100644 (file)
@@ -38,8 +38,8 @@ public:
   /// The decl must already be part of the decl chain.
   void RemoveDecl(NamedDecl *D);
 
-  /// Lookup - Find the non-shadowed decl that belongs to a particular
-  /// Decl::IdentifierNamespace.
+  /// Lookup - Find the non-shadowed decl that belongs to one or more
+  /// of the specified Decl::IdentifierNamespaces.
   NamedDecl *Lookup(const IdentifierInfo *II, unsigned NSI);
 
 private:
index c47a027fecee19f43c64ca71776df17d9e1cf8b1..328741ec0feeaf92d116c161b3d790047d9234c4 100644 (file)
@@ -35,7 +35,9 @@ using namespace clang;
 Sema::DeclTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S) {
   Decl *IIDecl = LookupDecl(&II, Decl::IDNS_Ordinary, S, false);
 
-  if (IIDecl && (isa<TypedefDecl>(IIDecl) || isa<ObjCInterfaceDecl>(IIDecl)))
+  if (IIDecl && (isa<TypedefDecl>(IIDecl) || 
+                 isa<ObjCInterfaceDecl>(IIDecl) ||
+                 isa<TagDecl>(IIDecl)))
     return IIDecl;
   return 0;
 }
@@ -102,7 +104,9 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) {
 Decl *Sema::LookupDecl(const IdentifierInfo *II, unsigned NSI,
                        Scope *S, bool enableLazyBuiltinCreation) {
   if (II == 0) return 0;
-  Decl::IdentifierNamespace NS = (Decl::IdentifierNamespace)NSI;
+  unsigned NS = NSI;
+  if (getLangOptions().CPlusPlus && (NS & Decl::IDNS_Ordinary))
+    NS |= Decl::IDNS_Tag;
 
   // Scan up the scope chain looking for a decl that matches this identifier
   // that is in the appropriate namespace.  This search should not take long, as
@@ -113,7 +117,7 @@ Decl *Sema::LookupDecl(const IdentifierInfo *II, unsigned NSI,
   // If we didn't find a use of this identifier, and if the identifier
   // corresponds to a compiler builtin, create the decl object for the builtin
   // now, injecting it into translation unit scope, and return it.
-  if (NS == Decl::IDNS_Ordinary) {
+  if (NS & Decl::IDNS_Ordinary) {
     if (enableLazyBuiltinCreation) {
       // If this is a builtin on this (or all) targets, create the decl.
       if (unsigned BuiltinID = II->getBuiltinID())
@@ -746,7 +750,13 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
   Decl *PrevDecl = LookupDecl(II, Decl::IDNS_Ordinary, S);
   ScopedDecl *New;
   bool InvalidDecl = false;
-  
+  // In C++, the previous declaration we find might be a tag type
+  // (class or enum). In this case, the new declaration will hide the
+  // tag type. 
+  if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
+    PrevDecl = 0;
+
   QualType R = GetTypeForDeclarator(D, S);
   assert(!R.isNull() && "GetTypeForDeclarator() returned null type");
 
index 223cb56636612d004963940e8f95dd99e21c9836..33797c425558817c016d6c95e000932d70b9c33d 100644 (file)
@@ -105,7 +105,7 @@ QualType Sema::ConvertDeclSpecToType(DeclSpec &DS) {
            DS.getTypeSpecSign() == 0 &&
            "Can't handle qualifiers on typedef names yet!");
     // TypeQuals handled by caller.
-    Result = Context.getTagDeclType(cast<TagDecl>(D));
+    Result = Context.getTypeDeclType(cast<TypeDecl>(D));
     break;
   }    
   case DeclSpec::TST_typedef: {
@@ -114,6 +114,7 @@ QualType Sema::ConvertDeclSpecToType(DeclSpec &DS) {
     assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 &&
            DS.getTypeSpecSign() == 0 &&
            "Can't handle qualifiers on typedef names yet!");
+
     // FIXME: Adding a TST_objcInterface clause doesn't seem ideal, so
     // we have this "hack" for now... 
     if (ObjCInterfaceDecl *ObjCIntDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
@@ -140,7 +141,7 @@ QualType Sema::ConvertDeclSpecToType(DeclSpec &DS) {
       }
     }
     // TypeQuals handled by caller.
-    Result = Context.getTypedefType(cast<TypedefDecl>(D));
+    Result = Context.getTypeDeclType(dyn_cast<TypeDecl>(D));
     break;
   }
   case DeclSpec::TST_typeofType:
diff --git a/test/Sema/class-names.cpp b/test/Sema/class-names.cpp
new file mode 100644 (file)
index 0000000..b78d696
--- /dev/null
@@ -0,0 +1,50 @@
+// RUN: clang -fsyntax-only -verify %s
+class C { };
+
+C c;
+
+void D(int);
+
+class D {}; // expected-error{{previous use is here}}
+
+void foo()
+{
+  D(5);
+  class D d;
+}
+
+class D; 
+
+enum D; // expected-error{{use of 'D' with tag type that does not match previous declaration}}
+
+class A * A;
+
+class A * a2;
+
+void bar()
+{
+  A = 0;
+}
+
+void C(int);
+
+void bar2()
+{
+  C(17);
+}
+
+extern int B;
+class B;
+class B {};
+int B;
+
+enum E { e1_val };
+E e1;
+
+void E(int);
+
+void bar3() {
+  E(17);
+}
+
+enum E e2;