From 2ce52f3fb95bf544db6bd3d91a72bce7d9cceb6c Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sun, 13 Apr 2008 21:07:44 +0000 Subject: [PATCH] Introduce support for finding class and enum names via ordinary name lookup in C++ git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@49621 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 6 +++- include/clang/AST/DeclBase.h | 12 ++++---- include/clang/AST/Type.h | 13 +++++---- lib/AST/ASTContext.cpp | 32 +++++++++++++++------ lib/Sema/IdentifierResolver.cpp | 27 +++++++++++++++--- lib/Sema/IdentifierResolver.h | 4 +-- lib/Sema/SemaDecl.cpp | 18 +++++++++--- lib/Sema/SemaType.cpp | 5 ++-- test/Sema/class-names.cpp | 50 +++++++++++++++++++++++++++++++++ 9 files changed, 135 insertions(+), 32 deletions(-) create mode 100644 test/Sema/class-names.cpp diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 2f669b131d..b29c23e3f7 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -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); diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 058cb9223c..a5c1cb29ec 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -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 diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 5d36b759a3..8b5ed4ce63 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -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(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(D), QualType()) { } + friend class ASTContext; // ASTContext creates these. public: EnumDecl *getDecl() const { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 5af59aadd3..e4b48e21e4 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -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(Decl)) + return getTypedefType(Typedef); + else if (ObjCInterfaceDecl *ObjCInterface + = dyn_cast_or_null(Decl)) + return getObjCInterfaceType(ObjCInterface); + else if (RecordDecl *Record = dyn_cast_or_null(Decl)) { + Decl->TypeForDecl = new RecordType(Record); + Types.push_back(Decl->TypeForDecl); + return QualType(Decl->TypeForDecl, 0); + } else if (EnumDecl *Enum = dyn_cast_or_null(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 diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp index 79898e4380..037802c640 100644 --- a/lib/Sema/IdentifierResolver.cpp +++ b/lib/Sema/IdentifierResolver.cpp @@ -15,6 +15,7 @@ #include "IdentifierResolver.h" #include "clang/Basic/IdentifierTable.h" #include "clang/AST/Decl.h" +#include "clang/Parse/Scope.h" #include #include @@ -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(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(); if (!Ptr) return NULL; if (isDeclPtr(Ptr)) { NamedDecl *D = static_cast(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; } diff --git a/lib/Sema/IdentifierResolver.h b/lib/Sema/IdentifierResolver.h index bdaab694fe..abe568d602 100644 --- a/lib/Sema/IdentifierResolver.h +++ b/lib/Sema/IdentifierResolver.h @@ -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: diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c47a027fec..328741ec0f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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(IIDecl) || isa(IIDecl))) + if (IIDecl && (isa(IIDecl) || + isa(IIDecl) || + isa(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"); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 223cb56636..33797c4255 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -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(D)); + Result = Context.getTypeDeclType(cast(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(D)) { @@ -140,7 +141,7 @@ QualType Sema::ConvertDeclSpecToType(DeclSpec &DS) { } } // TypeQuals handled by caller. - Result = Context.getTypedefType(cast(D)); + Result = Context.getTypeDeclType(dyn_cast(D)); break; } case DeclSpec::TST_typeofType: diff --git a/test/Sema/class-names.cpp b/test/Sema/class-names.cpp new file mode 100644 index 0000000000..b78d6964e2 --- /dev/null +++ b/test/Sema/class-names.cpp @@ -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; -- 2.40.0