From: Argyrios Kyrtzidis Date: Wed, 10 Nov 2010 05:40:41 +0000 (+0000) Subject: Replace UsingDecl's SmallPtrSet of UsingShadowDecls with a linked list to avoid leaki... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=826faa22bae112e01293a58534a40711043cce65;p=clang Replace UsingDecl's SmallPtrSet of UsingShadowDecls with a linked list to avoid leaking memory. Fixes rdar://8649963. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@118674 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 91653340aa..53f04fd79a 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1881,13 +1881,16 @@ class UsingShadowDecl : public NamedDecl { /// The referenced declaration. NamedDecl *Underlying; - /// The using declaration which introduced this decl. - UsingDecl *Using; + /// \brief The using declaration which introduced this decl or the next using + /// shadow declaration contained in the aforementioned using declaration. + NamedDecl *UsingOrNextShadow; + friend class UsingDecl; UsingShadowDecl(DeclContext *DC, SourceLocation Loc, UsingDecl *Using, NamedDecl *Target) : NamedDecl(UsingShadow, DC, Loc, DeclarationName()), - Underlying(Target), Using(Using) { + Underlying(Target), + UsingOrNextShadow(reinterpret_cast(Using)) { if (Target) { setDeclName(Target->getDeclName()); IdentifierNamespace = Target->getIdentifierNamespace(); @@ -1915,15 +1918,20 @@ public: } /// \brief Gets the using declaration to which this declaration is tied. - UsingDecl *getUsingDecl() const { return Using; } + UsingDecl *getUsingDecl() const; - /// \brief Sets the using declaration that introduces this target - /// declaration. - void setUsingDecl(UsingDecl* UD) { Using = UD; } + /// \brief The next using shadow declaration contained in the shadow decl + /// chain of the using declaration which introduced this decl. + UsingShadowDecl *getNextUsingShadowDecl() const { + return dyn_cast_or_null(UsingOrNextShadow); + } static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const UsingShadowDecl *D) { return true; } static bool classofKind(Kind K) { return K == Decl::UsingShadow; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; }; /// UsingDecl - Represents a C++ using-declaration. For example: @@ -1943,10 +1951,9 @@ class UsingDecl : public NamedDecl { /// declaration name embedded in the ValueDecl base class. DeclarationNameLoc DNLoc; - /// \brief The collection of shadow declarations associated with - /// this using declaration. This set can change as a class is - /// processed. - llvm::SmallPtrSet Shadows; + /// \brief The first shadow declaration of the shadow decl chain associated + /// with this using declaration. + UsingShadowDecl *FirstUsingShadow; // \brief Has 'typename' keyword. bool IsTypeName; @@ -1956,7 +1963,7 @@ class UsingDecl : public NamedDecl { const DeclarationNameInfo &NameInfo, bool IsTypeNameArg) : NamedDecl(Using, DC, NameInfo.getLoc(), NameInfo.getName()), NestedNameRange(NNR), UsingLocation(UL), TargetNestedName(TargetNNS), - DNLoc(NameInfo.getInfo()), IsTypeName(IsTypeNameArg) { + DNLoc(NameInfo.getInfo()), FirstUsingShadow(0),IsTypeName(IsTypeNameArg) { } public: @@ -1994,29 +2001,58 @@ public: /// \brief Sets whether the using declaration has 'typename'. void setTypeName(bool TN) { IsTypeName = TN; } - typedef llvm::SmallPtrSet::const_iterator shadow_iterator; - shadow_iterator shadow_begin() const { return Shadows.begin(); } - shadow_iterator shadow_end() const { return Shadows.end(); } + /// \brief Iterates through the using shadow declarations assosiated with + /// this using declaration. + class shadow_iterator { + /// \brief The current using shadow declaration. + UsingShadowDecl *Current; + + public: + typedef UsingShadowDecl* value_type; + typedef UsingShadowDecl* reference; + typedef UsingShadowDecl* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + shadow_iterator() : Current(0) { } + explicit shadow_iterator(UsingShadowDecl *C) : Current(C) { } + + reference operator*() const { return Current; } + pointer operator->() const { return Current; } - void addShadowDecl(UsingShadowDecl *S) { - assert(S->getUsingDecl() == this); - if (!Shadows.insert(S)) { - assert(false && "declaration already in set"); + shadow_iterator& operator++() { + Current = Current->getNextUsingShadowDecl(); + return *this; } - } - void removeShadowDecl(UsingShadowDecl *S) { - assert(S->getUsingDecl() == this); - if (!Shadows.erase(S)) { - assert(false && "declaration not in set"); + + shadow_iterator operator++(int) { + shadow_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(shadow_iterator x, shadow_iterator y) { + return x.Current == y.Current; } + friend bool operator!=(shadow_iterator x, shadow_iterator y) { + return x.Current != y.Current; + } + }; + + shadow_iterator shadow_begin() const { + return shadow_iterator(FirstUsingShadow); } + shadow_iterator shadow_end() const { return shadow_iterator(); } /// \brief Return the number of shadowed declarations associated with this /// using declaration. - unsigned getNumShadowDecls() const { - return Shadows.size(); + unsigned shadow_size() const { + return std::distance(shadow_begin(), shadow_end()); } + void addShadowDecl(UsingShadowDecl *S); + void removeShadowDecl(UsingShadowDecl *S); + static UsingDecl *Create(ASTContext &C, DeclContext *DC, SourceRange NNR, SourceLocation UsingL, NestedNameSpecifier* TargetNNS, diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index bcb47baa24..7679bf8244 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -1276,6 +1276,44 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, Qualifier, IdentLoc, Namespace); } +UsingDecl *UsingShadowDecl::getUsingDecl() const { + const UsingShadowDecl *Shadow = this; + while (const UsingShadowDecl *NextShadow = + dyn_cast(Shadow->UsingOrNextShadow)) + Shadow = NextShadow; + return cast(Shadow->UsingOrNextShadow); +} + +void UsingDecl::addShadowDecl(UsingShadowDecl *S) { + assert(std::find(shadow_begin(), shadow_end(), S) == shadow_end() && + "declaration already in set"); + assert(S->getUsingDecl() == this); + + if (FirstUsingShadow) + S->UsingOrNextShadow = FirstUsingShadow; + FirstUsingShadow = S; +} + +void UsingDecl::removeShadowDecl(UsingShadowDecl *S) { + assert(std::find(shadow_begin(), shadow_end(), S) != shadow_end() && + "declaration not in set"); + assert(S->getUsingDecl() == this); + + // Remove S from the shadow decl chain. This is O(n) but hopefully rare. + + if (FirstUsingShadow == S) { + FirstUsingShadow = dyn_cast(S->UsingOrNextShadow); + S->UsingOrNextShadow = this; + return; + } + + UsingShadowDecl *Prev = FirstUsingShadow; + while (Prev->UsingOrNextShadow != S) + Prev = cast(Prev->UsingOrNextShadow); + Prev->UsingOrNextShadow = S->UsingOrNextShadow; + S->UsingOrNextShadow = this; +} + UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, SourceRange NNR, SourceLocation UL, NestedNameSpecifier* TargetNNS, diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 4fca0927cf..e49447063e 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -717,16 +717,7 @@ void ASTDeclReader::VisitUsingDecl(UsingDecl *D) { D->setNestedNameRange(ReadSourceRange(Record, Idx)); D->setTargetNestedNameDecl(Reader.ReadNestedNameSpecifier(Record, Idx)); ReadDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record, Idx); - - // FIXME: It would probably be more efficient to read these into a vector - // and then re-cosntruct the shadow decl set over that vector since it - // would avoid existence checks. - unsigned NumShadows = Record[Idx++]; - for(unsigned I = 0; I != NumShadows; ++I) { - // Avoid invariant checking of UsingDecl::addShadowDecl, the decl may still - // be initializing. - D->Shadows.insert(cast(Reader.GetDecl(Record[Idx++]))); - } + D->FirstUsingShadow = cast_or_null(Reader.GetDecl(Record[Idx++])); D->setTypeName(Record[Idx++]); NamedDecl *Pattern = cast_or_null(Reader.GetDecl(Record[Idx++])); if (Pattern) @@ -736,7 +727,7 @@ void ASTDeclReader::VisitUsingDecl(UsingDecl *D) { void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) { VisitNamedDecl(D); D->setTargetDecl(cast(Reader.GetDecl(Record[Idx++]))); - D->setUsingDecl(cast(Reader.GetDecl(Record[Idx++]))); + D->UsingOrNextShadow = cast_or_null(Reader.GetDecl(Record[Idx++])); UsingShadowDecl *Pattern = cast_or_null(Reader.GetDecl(Record[Idx++])); if (Pattern) diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index de58cd03a4..609a04432b 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -673,10 +673,7 @@ void ASTDeclWriter::VisitUsingDecl(UsingDecl *D) { Writer.AddSourceLocation(D->getUsingLocation(), Record); Writer.AddNestedNameSpecifier(D->getTargetNestedNameDecl(), Record); Writer.AddDeclarationNameLoc(D->DNLoc, D->getDeclName(), Record); - Record.push_back(D->getNumShadowDecls()); - for (UsingDecl::shadow_iterator P = D->shadow_begin(), - PEnd = D->shadow_end(); P != PEnd; ++P) - Writer.AddDeclRef(*P, Record); + Writer.AddDeclRef(D->FirstUsingShadow, Record); Record.push_back(D->isTypeName()); Writer.AddDeclRef(Context.getInstantiatedFromUsingDecl(D), Record); Code = serialization::DECL_USING; @@ -685,7 +682,7 @@ void ASTDeclWriter::VisitUsingDecl(UsingDecl *D) { void ASTDeclWriter::VisitUsingShadowDecl(UsingShadowDecl *D) { VisitNamedDecl(D); Writer.AddDeclRef(D->getTargetDecl(), Record); - Writer.AddDeclRef(D->getUsingDecl(), Record); + Writer.AddDeclRef(D->UsingOrNextShadow, Record); Writer.AddDeclRef(Context.getInstantiatedFromUsingShadowDecl(D), Record); Code = serialization::DECL_USING_SHADOW; } diff --git a/test/Index/load-namespaces.cpp b/test/Index/load-namespaces.cpp index 31e2fce735..931a1dc79d 100644 --- a/test/Index/load-namespaces.cpp +++ b/test/Index/load-namespaces.cpp @@ -41,7 +41,7 @@ namespace my_rel_ops = std::rel_ops; // CHECK: load-namespaces.cpp:18:11: Namespace=std:18:11 (Definition) Extent=[18:11 - 20:2] // CHECK: load-namespaces.cpp:19:7: FunctionDecl=g:19:7 Extent=[19:7 - 19:13] // CHECK: load-namespaces.cpp:19:12: ParmDecl=:19:12 (Definition) Extent=[19:9 - 19:13] -// CHECK: load-namespaces.cpp:22:12: UsingDeclaration=g[10:8, 19:7] Extent=[22:1 - 22:13] +// CHECK: load-namespaces.cpp:22:12: UsingDeclaration=g[19:7, 10:8] Extent=[22:1 - 22:13] // CHECK: load-namespaces.cpp:22:7: NamespaceRef=std:18:11 Extent=[22:7 - 22:10] // CHECK: load-namespaces.cpp:24:11: FunctionDecl=g:24:11 (Definition) Extent=[24:11 - 25:2] // CHECK: load-namespaces.cpp:24:6: NamespaceRef=std:18:11 Extent=[24:6 - 24:9] diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 454255516f..30e903449f 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -3645,7 +3645,7 @@ unsigned clang_getNumOverloadedDecls(CXCursor C) { Decl *D = Storage.get(); if (UsingDecl *Using = dyn_cast(D)) - return Using->getNumShadowDecls(); + return Using->shadow_size(); if (ObjCClassDecl *Classes = dyn_cast(D)) return Classes->size(); if (ObjCForwardProtocolDecl *Protocols =dyn_cast(D))