diff options
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/IdentifierResolver.cpp | 205 | ||||
-rw-r--r-- | lib/Sema/IdentifierResolver.h | 345 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 72 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 3 | ||||
-rw-r--r-- | test/Sema/cxx-namespace.cpp | 40 |
6 files changed, 493 insertions, 175 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 65f1124e63..f20c72e61c 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1251,7 +1251,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D) { // Enter function-declaration scope, limiting any declarators to the // function prototype scope, including parameter declarators. - EnterScope(Scope::DeclScope); + EnterScope(Scope::FnScope|Scope::DeclScope); bool IsVariadic = false; while (1) { @@ -1526,3 +1526,4 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { } } + diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp index 57e8d0a103..fada62f10b 100644 --- a/lib/Sema/IdentifierResolver.cpp +++ b/lib/Sema/IdentifierResolver.cpp @@ -13,67 +13,16 @@ //===----------------------------------------------------------------------===// #include "IdentifierResolver.h" -#include "clang/Basic/IdentifierTable.h" -#include "clang/AST/Decl.h" -#include "clang/Parse/Scope.h" #include <list> #include <vector> using namespace clang; -namespace { - -class IdDeclInfo; - -/// Identifier's FETokenInfo contains a Decl pointer if lower bit == 0. -static inline bool isDeclPtr(void *Ptr) { - return (reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 0; -} - -/// Identifier's FETokenInfo contains a IdDeclInfo pointer if lower bit == 1. -static inline IdDeclInfo *toIdDeclInfo(void *Ptr) { - return reinterpret_cast<IdDeclInfo*>( - reinterpret_cast<uintptr_t>(Ptr) & ~0x1 - ); -} - - -/// IdDeclInfo - Keeps track of information about decls associated to a -/// particular identifier. IdDeclInfos are lazily constructed and assigned -/// to an identifier the first time a decl with that identifier is shadowed -/// in some scope. -class IdDeclInfo { - typedef llvm::SmallVector<NamedDecl *, 2> ShadowedTy; - ShadowedTy ShadowedDecls; - -public: - typedef ShadowedTy::iterator ShadowedIter; - - inline ShadowedIter shadowed_begin() { return ShadowedDecls.begin(); } - inline ShadowedIter shadowed_end() { return ShadowedDecls.end(); } - - /// Add a decl in the scope chain. - void PushShadowed(NamedDecl *D) { - assert(D && "Decl null"); - ShadowedDecls.push_back(D); - } - - /// Add the decl at the top of scope chain. - void PushGlobalShadowed(NamedDecl *D) { - assert(D && "Decl null"); - ShadowedDecls.insert(ShadowedDecls.begin(), D); - } - - /// RemoveShadowed - Remove the decl from the scope chain. - /// The decl must already be part of the decl chain. - void RemoveShadowed(NamedDecl *D); -}; - /// IdDeclInfoMap - Associates IdDeclInfos with Identifiers. /// Allocates 'pools' (vectors of IdDeclInfos) to avoid allocating each /// individual IdDeclInfo to heap. -class IdDeclInfoMap { +class IdentifierResolver::IdDeclInfoMap { static const unsigned int VECTOR_SIZE = 512; // Holds vectors of IdDeclInfos that serve as 'pools'. // New vectors are added when the current one is full. @@ -88,17 +37,14 @@ public: IdDeclInfo &operator[](IdentifierInfo *II); }; -} // end anonymous namespace - IdentifierResolver::IdentifierResolver() : IdDeclInfos(new IdDeclInfoMap) {} IdentifierResolver::~IdentifierResolver() { - delete static_cast<IdDeclInfoMap*>(IdDeclInfos); + delete IdDeclInfos; } /// AddDecl - Link the decl to its shadowed decl chain. -void IdentifierResolver::AddDecl(NamedDecl *D, Scope *S) { - assert(D && S && "null param passed"); +void IdentifierResolver::AddDecl(NamedDecl *D) { IdentifierInfo *II = D->getIdentifier(); void *Ptr = II->getFETokenInfo<void>(); @@ -111,56 +57,40 @@ void IdentifierResolver::AddDecl(NamedDecl *D, Scope *S) { if (isDeclPtr(Ptr)) { II->setFETokenInfo(NULL); - IdDeclInfoMap &Map = *static_cast<IdDeclInfoMap*>(IdDeclInfos); - IDI = &Map[II]; - IDI->PushShadowed(static_cast<NamedDecl*>(Ptr)); + IDI = &(*IdDeclInfos)[II]; + NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr); + IDI->AddDecl(PrevD); } 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) && IDI->shadowed_end() != IDI->shadowed_begin()) { - // 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); + IDI->AddDecl(D); } -/// AddGlobalDecl - Link the decl at the top of the shadowed decl chain. -void IdentifierResolver::AddGlobalDecl(NamedDecl *D) { - assert(D && "null param passed"); +/// AddShadowedDecl - Link the decl to its shadowed decl chain putting it +/// after the decl that the iterator points to, thus the 'CIT' decl will be +/// encountered before the 'D' decl. +void IdentifierResolver::AddShadowedDecl(NamedDecl *D, NamedDecl *Shadow) { + assert(D->getIdentifier() == Shadow->getIdentifier() && "Different ids!"); + assert(LookupContext(D) == LookupContext(Shadow) && "Different context!"); + IdentifierInfo *II = D->getIdentifier(); void *Ptr = II->getFETokenInfo<void>(); - - if (!Ptr) { - II->setFETokenInfo(D); - return; - } + assert(Ptr && "No decl from Ptr ?"); IdDeclInfo *IDI; if (isDeclPtr(Ptr)) { II->setFETokenInfo(NULL); - IdDeclInfoMap &Map = *static_cast<IdDeclInfoMap*>(IdDeclInfos); - IDI = &Map[II]; - IDI->PushShadowed(static_cast<NamedDecl*>(Ptr)); - } else - IDI = toIdDeclInfo(Ptr); + IDI = &(*IdDeclInfos)[II]; + NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr); + assert(PrevD == Shadow && "Invalid shadow decl ?"); + IDI->AddDecl(D); + IDI->AddDecl(PrevD); + return; + } - IDI->PushGlobalShadowed(D); + IDI = toIdDeclInfo(Ptr); + IDI->AddShadowed(D, Shadow); } /// RemoveDecl - Unlink the decl from its shadowed decl chain. @@ -178,71 +108,72 @@ void IdentifierResolver::RemoveDecl(NamedDecl *D) { return; } - return toIdDeclInfo(Ptr)->RemoveShadowed(D); + return toIdDeclInfo(Ptr)->RemoveDecl(D); } -/// Lookup - Find the non-shadowed decl that belongs to a particular -/// Decl::IdentifierNamespace. -NamedDecl *IdentifierResolver::Lookup(const IdentifierInfo *II, unsigned NS) { - assert(II && "null param passed"); +/// begin - Returns an iterator for all decls, starting at the given +/// declaration context. +IdentifierResolver::iterator +IdentifierResolver::begin(const IdentifierInfo *II, DeclContext *Ctx) { + assert(Ctx && "null param passed"); + void *Ptr = II->getFETokenInfo<void>(); + if (!Ptr) return end(II); - if (!Ptr) return NULL; + LookupContext LC(Ctx); if (isDeclPtr(Ptr)) { NamedDecl *D = static_cast<NamedDecl*>(Ptr); - return (D->getIdentifierNamespace() & NS) ? D : NULL; - } - IdDeclInfo *IDI = toIdDeclInfo(Ptr); + if (LC.isEqOrContainedBy(LookupContext(D))) + return iterator(D); + else + return end(II); - // ShadowedDecls are ordered from most shadowed to less shadowed. - // So we do a reverse iteration from end to begin. - for (IdDeclInfo::ShadowedIter SI = IDI->shadowed_end(); - SI != IDI->shadowed_begin(); --SI) { - NamedDecl *D = *(SI-1); - if (D->getIdentifierNamespace() & NS) - return D; } - - // we didn't find the decl. - return NULL; + + IdDeclInfo *IDI = toIdDeclInfo(Ptr); + return iterator(IDI->FindContext(LC)); } -/// RemoveShadowed - Remove the decl from the scope chain. -/// The decl must already be part of the decl chain. -void IdDeclInfo::RemoveShadowed(NamedDecl *D) { - assert(D && "null decl passed"); - assert(!ShadowedDecls.empty() && - "Didn't find this decl on its identifier's chain!"); - - // common case - if (D == ShadowedDecls.back()) { - ShadowedDecls.pop_back(); - return; - } +/// ctx_begin - Returns an iterator for only decls that belong to the given +/// declaration context. +IdentifierResolver::ctx_iterator +IdentifierResolver::ctx_begin(const IdentifierInfo *II, DeclContext *Ctx) { + assert(Ctx && "null param passed"); + + void *Ptr = II->getFETokenInfo<void>(); + if (!Ptr) return ctx_end(II); + + LookupContext LC(Ctx); + + if (isDeclPtr(Ptr)) { + NamedDecl *D = static_cast<NamedDecl*>(Ptr); + + if (LC == LookupContext(D)) + return ctx_iterator(D); + else + return ctx_end(II); - for (ShadowedIter SI = ShadowedDecls.end()-1; - SI != ShadowedDecls.begin(); --SI) { - if (*(SI-1) == D) { - ShadowedDecls.erase(SI-1); - return; - } } + + IdDeclInfo *IDI = toIdDeclInfo(Ptr); + IdDeclInfo::DeclsTy::iterator I = IDI->FindContext(LookupContext(Ctx)); + if (I != IDI->decls_begin() && LC != LookupContext(*(I-1))) + I = IDI->decls_begin(); - assert(false && "Didn't find this decl on its identifier's chain!"); + return ctx_iterator(I); } + /// Returns the IdDeclInfo associated to the IdentifierInfo. /// It creates a new IdDeclInfo if one was not created before for this id. -IdDeclInfo &IdDeclInfoMap::operator[](IdentifierInfo *II) { +IdentifierResolver::IdDeclInfo & +IdentifierResolver::IdDeclInfoMap::operator[](IdentifierInfo *II) { assert (II && "null IdentifierInfo passed"); void *Ptr = II->getFETokenInfo<void>(); - if (Ptr) { - assert(!isDeclPtr(Ptr) && "didn't clear decl for FEToken"); - return *toIdDeclInfo(Ptr); - } + if (Ptr) return *toIdDeclInfo(Ptr); if (CurIndex == VECTOR_SIZE) { // Add a IdDeclInfo vector 'pool' diff --git a/lib/Sema/IdentifierResolver.h b/lib/Sema/IdentifierResolver.h index 34b4764d14..da1327be48 100644 --- a/lib/Sema/IdentifierResolver.h +++ b/lib/Sema/IdentifierResolver.h @@ -15,37 +15,354 @@ #ifndef LLVM_CLANG_AST_SEMA_IDENTIFIERRESOLVER_H #define LLVM_CLANG_AST_SEMA_IDENTIFIERRESOLVER_H +#include "clang/Basic/IdentifierTable.h" +#include "clang/Parse/Scope.h" +#include "clang/AST/Decl.h" + namespace clang { - class IdentifierInfo; - class NamedDecl; - class Scope; /// IdentifierResolver - Keeps track of shadowed decls on enclosing scopes. /// It manages the shadowing chains of identifiers and implements efficent decl /// lookup based on an identifier. class IdentifierResolver { + + /// LookupContext - A wrapper for DeclContext. DeclContext is only part of + /// ScopedDecls, LookupContext can be used with all decls (assumes + /// translation unit context for non ScopedDecls). + class LookupContext { + DeclContext *Ctx; + + /// TUCtx - Provides a common value for translation unit context for all + /// decls. + /// FIXME: When (if ?) all decls can point to their translation unit context + /// remove this hack. + static inline DeclContext *TUCtx() { + return reinterpret_cast<DeclContext*>(-1); + } + + /// getContext - Returns translation unit context for non ScopedDecls and + /// for EnumConstantDecls returns the parent context of their EnumDecl. + static DeclContext *getContext(Decl *D) { + DeclContext *Ctx; + + if (EnumConstantDecl *EnumD = dyn_cast<EnumConstantDecl>(D)) { + Ctx = EnumD->getDeclContext()->getParent(); + } else if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) + Ctx = SD->getDeclContext(); + else + return TUCtx(); + + if (isa<TranslationUnitDecl>(Ctx)) + return TUCtx(); + + return Ctx; + } + + public: + LookupContext(Decl *D) { + Ctx = getContext(D); + } + LookupContext(DeclContext *DC) { + if (!DC || isa<TranslationUnitDecl>(DC)) + Ctx = TUCtx(); + else + Ctx = DC; + } + + bool isTU() const { + return (Ctx == TUCtx()); + } + + /// getParent - Returns the parent context. This should not be called for + /// a translation unit context. + LookupContext getParent() const { + assert(!isTU() && "TU has no parent!"); + return LookupContext(Ctx->getParent()); + } + + /// isEqOrContainedBy - Returns true of the given context is the same or a + /// parent of this one. + bool isEqOrContainedBy(const LookupContext &PC) const { + if (PC.isTU()) return true; + + for (LookupContext Next = *this; !Next.isTU(); Next = Next.getParent()) + if (Next.Ctx == PC.Ctx) return true; + + return false; + } + + bool operator==(const LookupContext &RHS) const { + return Ctx == RHS.Ctx; + } + bool operator!=(const LookupContext &RHS) const { + return Ctx != RHS.Ctx; + } + }; + + /// IdDeclInfo - Keeps track of information about decls associated to a + /// particular identifier. IdDeclInfos are lazily constructed and assigned + /// to an identifier the first time a decl with that identifier is shadowed + /// in some scope. + class IdDeclInfo { + public: + typedef llvm::SmallVector<NamedDecl*, 2> DeclsTy; + + inline DeclsTy::iterator decls_begin() { return Decls.begin(); } + inline DeclsTy::iterator decls_end() { return Decls.end(); } + + /// FindContext - Returns an iterator pointing just after the decl that is + /// in the given context or in a parent of it. The search is in reverse + /// order, from end to begin. + DeclsTy::iterator FindContext(const LookupContext &Ctx) { + return FindContext(Ctx, Decls.end()); + } + + /// FindContext - Returns an iterator pointing just after the decl that is + /// in the given context or in a parent of it. The search is in reverse + /// order, from end to begin. + DeclsTy::iterator FindContext(const LookupContext &Ctx, + const DeclsTy::iterator &Start) { + for (DeclsTy::iterator I = Start; I != Decls.begin(); --I) { + if (Ctx.isEqOrContainedBy(LookupContext(*(I-1)))) + return I; + } + + return Decls.begin(); + } + + /// iterator - Iterate over the decls by walking their parent contexts too. + class iterator { + public: + typedef DeclsTy::iterator BaseIter; + + iterator(const BaseIter &DeclIt) : DI(DeclIt) {} + const BaseIter &getBase() { return DI; } + + NamedDecl *&operator*() const { + return *(DI-1); + } + + bool operator==(const iterator &RHS) const { + return DI == RHS.DI; + } + bool operator!=(const iterator &RHS) const { + return DI != RHS.DI; + } + + // Preincrement. + iterator& operator++() { + NamedDecl *D = **this; + void *Ptr = D->getIdentifier()->getFETokenInfo<void>(); + assert(!isDeclPtr(Ptr) && "Decl with wrong id ?"); + DI = toIdDeclInfo(Ptr)->FindContext(LookupContext(D), DI-1); + return *this; + } + + private: + BaseIter DI; + }; + + /// ctx_iterator - Iterator over the decls of a specific context only. + class ctx_iterator { + public: + typedef DeclsTy::iterator BaseIter; + + ctx_iterator(const BaseIter &DeclIt) : DI(DeclIt) {} + const BaseIter &getBase() { return DI; } + + NamedDecl *&operator*() const { + return *(DI-1); + } + + bool operator==(const ctx_iterator &RHS) const { + return DI == RHS.DI; + } + bool operator!=(const ctx_iterator &RHS) const { + return DI != RHS.DI; + } + + // Preincrement. + ctx_iterator& operator++() { + NamedDecl *D = **this; + void *Ptr = D->getIdentifier()->getFETokenInfo<void>(); + assert(!isDeclPtr(Ptr) && "Decl with wrong id ?"); + IdDeclInfo *Info = toIdDeclInfo(Ptr); + + --DI; + if (DI != Info->Decls.begin() && + LookupContext(D) != LookupContext(**this)) + DI = Info->Decls.begin(); + return *this; + } + + private: + BaseIter DI; + }; + + void AddDecl(NamedDecl *D) { + Decls.insert(FindContext(LookupContext(D)), D); + } + + /// AddShadowed - Add a decl by putting it directly above the 'Shadow' decl. + /// Later lookups will find the 'Shadow' decl first. The 'Shadow' decl must + /// be already added to the scope chain and must be in the same context as + /// the decl that we want to add. + void AddShadowed(NamedDecl *D, NamedDecl *Shadow) { + assert(LookupContext(D) == LookupContext(Shadow) && + "Decl and Shadow not in same context!"); + + for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) { + if (Shadow == *(I-1)) { + Decls.insert(I-1, D); + return; + } + } + + assert(0 && "Shadow wasn't in scope chain!"); + } + + /// RemoveDecl - Remove the decl from the scope chain. + /// The decl must already be part of the decl chain. + void RemoveDecl(NamedDecl *D) { + for (DeclsTy::iterator I = Decls.end(); I != Decls.begin(); --I) { + if (D == *(I-1)) { + Decls.erase(I-1); + return; + } + } + + assert(0 && "Didn't find this decl on its identifier's chain!"); + } + + private: + DeclsTy Decls; + }; + + /// SwizzledIterator - Can be instantiated either with a single NamedDecl* + /// (the common case where only one decl is associated with an identifier) or + /// with an 'Iter' iterator, when there are more than one decls to lookup. + template<typename Iter> + class SwizzledIterator { + uintptr_t Ptr; + + SwizzledIterator() : Ptr(0) {} + SwizzledIterator(NamedDecl *D) { + Ptr = reinterpret_cast<uintptr_t>(D); + } + SwizzledIterator(Iter I) { + Ptr = reinterpret_cast<uintptr_t>(I.getBase()) | 0x1; + } + + bool isIterator() const { return (Ptr & 0x1); } + + Iter getIterator() const { + assert(isIterator() && "Ptr not an iterator."); + return reinterpret_cast<typename Iter::BaseIter>(Ptr & ~0x1); + } + + friend class IdentifierResolver; + public: + NamedDecl *operator*() const { + if (isIterator()) + return *getIterator(); + else + return reinterpret_cast<NamedDecl*>(Ptr); + } + + bool operator==(const SwizzledIterator &RHS) const { + return Ptr == RHS.Ptr; + } + bool operator!=(const SwizzledIterator &RHS) const { + return Ptr != RHS.Ptr; + } + + // Preincrement. + SwizzledIterator& operator++() { + if (isIterator()) { + Iter I = getIterator(); + ++I; + Ptr = reinterpret_cast<uintptr_t>(I.getBase()) | 0x1; + } + else // This is a single NamedDecl*. + Ptr = 0; + + return *this; + } + }; + public: - IdentifierResolver(); - ~IdentifierResolver(); + + typedef SwizzledIterator<IdDeclInfo::iterator> iterator; + typedef SwizzledIterator<IdDeclInfo::ctx_iterator> ctx_iterator; + + /// begin - Returns an iterator for all decls, starting at the given + /// declaration context. + static iterator begin(const IdentifierInfo *II, DeclContext *Ctx); + + static iterator end(const IdentifierInfo *II) { + void *Ptr = II->getFETokenInfo<void>(); + if (!Ptr || isDeclPtr(Ptr)) + return iterator(); + + IdDeclInfo *IDI = toIdDeclInfo(Ptr); + return iterator(IDI->decls_begin()); + } + + /// ctx_begin - Returns an iterator for only decls that belong to the given + /// declaration context. + static ctx_iterator ctx_begin(const IdentifierInfo *II, DeclContext *Ctx); + + static ctx_iterator ctx_end(const IdentifierInfo *II) { + void *Ptr = II->getFETokenInfo<void>(); + if (!Ptr || isDeclPtr(Ptr)) + return ctx_iterator(); + + IdDeclInfo *IDI = toIdDeclInfo(Ptr); + return ctx_iterator(IDI->decls_begin()); + } + + /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true
+ /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
+ /// true if 'D' belongs to the given declaration context.
+ static bool isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S = 0) { + if (Ctx->isFunctionOrMethod())
+ return S->isDeclScope(D);
+
+ return LookupContext(D) == LookupContext(Ctx); + } /// AddDecl - Link the decl to its shadowed decl chain. - void AddDecl(NamedDecl *D, Scope *S); + void AddDecl(NamedDecl *D); - /// AddGlobalDecl - Link the decl at the top of the shadowed decl chain. - void AddGlobalDecl(NamedDecl *D); + /// AddShadowedDecl - Link the decl to its shadowed decl chain putting it + /// after the decl that the iterator points to, thus the 'CIT' decl will be + /// encountered before the 'D' decl. + void AddShadowedDecl(NamedDecl *D, NamedDecl *Shadow); /// RemoveDecl - Unlink the decl from its shadowed decl chain. /// The decl must already be part of the decl chain. void RemoveDecl(NamedDecl *D); - /// Lookup - Find the non-shadowed decl that belongs to one or more - /// of the specified Decl::IdentifierNamespaces. - NamedDecl *Lookup(const IdentifierInfo *II, unsigned NSI); + IdentifierResolver(); + ~IdentifierResolver(); private: - // An instance of IdDeclInfoMap class, that's hidden away in the - // implementation file. - void *IdDeclInfos; + class IdDeclInfoMap; + IdDeclInfoMap *IdDeclInfos; + + /// Identifier's FETokenInfo contains a Decl pointer if lower bit == 0. + static inline bool isDeclPtr(void *Ptr) { + return (reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 0; + } + + /// Identifier's FETokenInfo contains a IdDeclInfo pointer if lower bit == 1. + static inline IdDeclInfo *toIdDeclInfo(void *Ptr) { + assert((reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 1 + && "Ptr not a IdDeclInfo* !"); + return reinterpret_cast<IdDeclInfo*>( + reinterpret_cast<uintptr_t>(Ptr) & ~0x1 + ); + } }; } // end namespace clang diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index afe877fb97..933a361812 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -59,13 +59,40 @@ void Sema::PopDeclContext() { /// Add this decl to the scope shadowed decl chains. void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) { - IdResolver.AddDecl(D, S); S->AddDecl(D); + + // 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 (TagDecl *TD = dyn_cast<TagDecl>(D)) { + // We are pushing the name of a tag (enum or class). + IdentifierResolver::ctx_iterator + CIT = IdResolver.ctx_begin(TD->getIdentifier(), TD->getDeclContext()); + if (CIT != IdResolver.ctx_end(TD->getIdentifier()) && + IdResolver.isDeclInScope(*CIT, TD->getDeclContext(), S)) { + // 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 chain. + + IdResolver.AddShadowedDecl(TD, *CIT); + return; + } + } + + IdResolver.AddDecl(D); } void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (S->decl_empty()) return; assert((S->getFlags() & Scope::DeclScope) &&"Scope shouldn't contain decls!"); + + // We only want to remove the decls from the identifier decl chains for local + // scopes, when inside a function/method. + if (S->getFnParent() == 0) + return; for (Scope::decl_iterator I = S->decl_begin(), E = S->decl_end(); I != E; ++I) { @@ -115,8 +142,10 @@ Decl *Sema::LookupDecl(const IdentifierInfo *II, unsigned NSI, // 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 // shadowing of names is uncommon, and deep shadowing is extremely uncommon. - NamedDecl *ND = IdResolver.Lookup(II, NS); - if (ND) return ND; + for (IdentifierResolver::iterator + I = IdResolver.begin(II, CurContext), E = IdResolver.end(II); I != E; ++I) + if ((*I)->getIdentifierNamespace() & NS) + return *I; // 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 @@ -184,11 +213,7 @@ ScopedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, // TUScope is the translation-unit scope to insert this function into. - TUScope->AddDecl(New); - - // Add this decl to the end of the identifier info. - IdResolver.AddGlobalDecl(New); - + PushOnScopeChains(New, TUScope); return New; } @@ -797,12 +822,12 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { D.getAttributes()); // Merge the decl with the existing one if appropriate. If the decl is // in an outer scope, it isn't the same thing. - if (PrevDecl && S->isDeclScope(PrevDecl)) { + if (PrevDecl && IdResolver.isDeclInScope(PrevDecl, CurContext, S)) { NewTD = MergeTypeDefDecl(NewTD, PrevDecl); if (NewTD == 0) return 0; } New = NewTD; - if (S->getParent() == 0) { + if (S->getFnParent() == 0) { // C99 6.7.7p2: If a typedef name specifies a variably modified type // then it shall have block scope. if (NewTD->getUnderlyingType()->isVariablyModifiedType()) { @@ -873,7 +898,9 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { // Merge the decl with the existing one if appropriate. Since C functions // are in a flat namespace, make sure we consider decls in outer scopes. - if (PrevDecl) { + if (PrevDecl && + (!getLangOptions().CPlusPlus || + IdResolver.isDeclInScope(PrevDecl, CurContext, S)) ) { bool Redeclaration = false; NewFD = MergeFunctionDecl(NewFD, PrevDecl, Redeclaration); if (NewFD == 0) return 0; @@ -914,7 +941,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { case DeclSpec::SCS_register: SC = VarDecl::Register; break; case DeclSpec::SCS_private_extern: SC = VarDecl::PrivateExtern; break; } - if (S->getParent() == 0) { + if (S->getFnParent() == 0) { // C99 6.9p2: The storage-class specifiers auto and register shall not // appear in the declaration specifiers in an external declaration. if (SC == VarDecl::Auto || SC == VarDecl::Register) { @@ -942,7 +969,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { } // Merge the decl with the existing one if appropriate. If the decl is // in an outer scope, it isn't the same thing. - if (PrevDecl && S->isDeclScope(PrevDecl)) { + if (PrevDecl && IdResolver.isDeclInScope(PrevDecl, CurContext, S)) { NewVD = MergeVarDecl(NewVD, PrevDecl); if (NewVD == 0) return 0; } @@ -1221,12 +1248,14 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { // See if this is a redefinition. Decl *PrevDcl = LookupDecl(D.getIdentifier(), Decl::IDNS_Ordinary, GlobalScope); - if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(PrevDcl)) { - const FunctionDecl *Definition; - if (FD->getBody(Definition)) { - Diag(D.getIdentifierLoc(), diag::err_redefinition, - D.getIdentifier()->getName()); - Diag(Definition->getLocation(), diag::err_previous_definition); + if (PrevDcl && IdResolver.isDeclInScope(PrevDcl, CurContext)) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(PrevDcl)) { + const FunctionDecl *Definition; + if (FD->getBody(Definition)) { + Diag(D.getIdentifierLoc(), diag::err_redefinition, + D.getIdentifier()->getName()); + Diag(Definition->getLocation(), diag::err_previous_definition); + } } } Decl *decl = static_cast<Decl*>(ActOnDeclarator(GlobalScope, D, 0)); @@ -1375,7 +1404,8 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, // If this is a use of a previous tag, or if the tag is already declared in // the same scope (so that the definition/declaration completes or // rementions the tag), reuse the decl. - if (TK == TK_Reference || S->isDeclScope(PrevDecl)) { + if (TK == TK_Reference || + IdResolver.isDeclInScope(PrevDecl, CurContext, S)) { // Make sure that this wasn't declared as an enum and now used as a struct // or something similar. if (PrevDecl->getKind() != Kind) { @@ -1733,7 +1763,7 @@ Sema::DeclTy *Sema::ActOnEnumConstant(Scope *S, DeclTy *theEnumDecl, // Verify that there isn't already something declared with this name in this // scope. if (Decl *PrevDecl = LookupDecl(Id, Decl::IDNS_Ordinary, S)) { - if (S->isDeclScope(PrevDecl)) { + if (IdResolver.isDeclInScope(PrevDecl, CurContext, S)) { if (isa<EnumConstantDecl>(PrevDecl)) Diag(IdLoc, diag::err_redefinition_of_enumerator, Id->getName()); else diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index c3b6bce447..f403858e75 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -335,7 +335,8 @@ Sema::DeclTy *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, LookupDecl(II, Decl::IDNS_Tag | Decl::IDNS_Ordinary, DeclRegionScope, /*enableLazyBuiltinCreation=*/false); - if (PrevDecl && DeclRegionScope->isDeclScope(PrevDecl)) { + if (PrevDecl && + IdResolver.isDeclInScope(PrevDecl, CurContext, DeclRegionScope)) { if (NamespaceDecl *OrigNS = dyn_cast<NamespaceDecl>(PrevDecl)) { // This is an extended namespace definition. // Attach this namespace decl to the chain of extended namespace diff --git a/test/Sema/cxx-namespace.cpp b/test/Sema/cxx-namespace.cpp index 05b791c83d..df0fa253ef 100644 --- a/test/Sema/cxx-namespace.cpp +++ b/test/Sema/cxx-namespace.cpp @@ -8,8 +8,46 @@ void f() { A = 0; } // expected-error {{error: unexpected namespace name 'A': ex int A; // expected-error {{error: redefinition of 'A' as different kind of symbol}} class A; // expected-error {{error: redefinition of 'A' as different kind of symbol}} -class B; // expected-error {{error: previous definition is here}} +class B {}; // expected-error {{error: previous definition is here}} namespace B {} // expected-error {{error: redefinition of 'B' as different kind of symbol}} void C(); // expected-error {{error: previous definition is here}} namespace C {} // expected-error {{error: redefinition of 'C' as different kind of symbol}} + +namespace S1 { + int x; + + namespace S2 { + + namespace S3 { + B x; + } + } +} + +namespace S1 { + void f() { + x = 0; + } + + namespace S2 { + + namespace S3 { + void f() { + x = 0; // expected-error {{error: incompatible type assigning 'int', expected 'class B'}} + } + } + + int y; + } +} + +namespace S1 { + namespace S2 { + namespace S3 { + void f3() { + y = 0; + } + } + } +} |