diff options
author | Vassil Vassilev <v.g.vassilev@gmail.com> | 2021-03-17 08:56:05 +0000 |
---|---|---|
committer | Vassil Vassilev <v.g.vassilev@gmail.com> | 2021-03-17 08:59:04 +0000 |
commit | 0cb7e7ca0c864e052bf49978f3bcd667c9e16930 (patch) | |
tree | e379b22e8130e19c619d5101e00ae7c475fd7915 /clang/lib/Sema | |
parent | 3b8b5d1f22f2c5d8ae55709a92d02011dea056ca (diff) | |
download | llvm-0cb7e7ca0c864e052bf49978f3bcd667c9e16930.zip llvm-0cb7e7ca0c864e052bf49978f3bcd667c9e16930.tar.gz llvm-0cb7e7ca0c864e052bf49978f3bcd667c9e16930.tar.bz2 |
Make iteration over the DeclContext::lookup_result safe.
The idiom:
```
DeclContext::lookup_result R = DeclContext::lookup(Name);
for (auto *D : R) {...}
```
is not safe when in the loop body we trigger deserialization from an AST file.
The deserialization can insert new declarations in the StoredDeclsList whose
underlying type is a vector. When the vector decides to reallocate its storage
the pointer we hold becomes invalid.
This patch replaces a SmallVector with an singly-linked list. The current
approach stores a SmallVector<NamedDecl*, 4> which is around 8 pointers.
The linked list is 3, 5, or 7. We do better in terms of memory usage for small
cases (and worse in terms of locality -- the linked list entries won't be near
each other, but will be near their corresponding declarations, and we were going
to fetch those memory pages anyway). For larger cases: the vector uses a
doubling strategy for reallocation, so will generally be between half-full and
full. Let's say it's 75% full on average, so there's N * 4/3 + 4 pointers' worth
of space allocated currently and will be 2N pointers with the linked list. So we
break even when there are N=6 entries and slightly lose in terms of memory usage
after that. We suspect that's still a win on average.
Thanks to @rsmith!
Differential revision: https://reviews.llvm.org/D91524
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/MultiplexExternalSemaSource.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 33 | ||||
-rw-r--r-- | clang/lib/Sema/SemaObjCProperty.cpp | 40 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 3 |
5 files changed, 41 insertions, 52 deletions
diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp index 252008c..3a993e2 100644 --- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -10,7 +10,6 @@ // //===----------------------------------------------------------------------===// #include "clang/Sema/MultiplexExternalSemaSource.h" -#include "clang/AST/DeclContextInternals.h" #include "clang/Sema/Lookup.h" using namespace clang; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 0365d77..10f61d8 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4130,13 +4130,9 @@ ValueDecl *Sema::tryLookupCtorInitMemberDecl(CXXRecordDecl *ClassDecl, IdentifierInfo *MemberOrBase) { if (SS.getScopeRep() || TemplateTypeTy) return nullptr; - DeclContext::lookup_result Result = ClassDecl->lookup(MemberOrBase); - if (Result.empty()) - return nullptr; - ValueDecl *Member; - if ((Member = dyn_cast<FieldDecl>(Result.front())) || - (Member = dyn_cast<IndirectFieldDecl>(Result.front()))) - return Member; + for (auto *D : ClassDecl->lookup(MemberOrBase)) + if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) + return cast<ValueDecl>(D); return nullptr; } @@ -9672,9 +9668,9 @@ public: bool foundSameNameMethod = false; SmallVector<CXXMethodDecl *, 8> overloadedMethods; - for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty(); - Path.Decls = Path.Decls.slice(1)) { - NamedDecl *D = Path.Decls.front(); + for (Path.Decls = BaseRecord->lookup(Name).begin(); + Path.Decls != DeclContext::lookup_iterator(); ++Path.Decls) { + NamedDecl *D = *Path.Decls; if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { MD = MD->getCanonicalDecl(); foundSameNameMethod = true; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index b6bf882..fef96b2 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -638,8 +638,8 @@ void LookupResult::resolveKind() { void LookupResult::addDeclsFromBasePaths(const CXXBasePaths &P) { CXXBasePaths::const_paths_iterator I, E; for (I = P.begin(), E = P.end(); I != E; ++I) - for (DeclContext::lookup_iterator DI = I->Decls.begin(), - DE = I->Decls.end(); DI != DE; ++DI) + for (DeclContext::lookup_iterator DI = I->Decls, DE = DI.end(); DI != DE; + ++DI) addDecl(*DI); } @@ -2230,9 +2230,9 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, CXXRecordDecl *BaseRecord = Specifier->getType()->getAsCXXRecordDecl(); // Drop leading non-matching lookup results from the declaration list so // we don't need to consider them again below. - for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty(); - Path.Decls = Path.Decls.slice(1)) { - if (Path.Decls.front()->isInIdentifierNamespace(IDNS)) + for (Path.Decls = BaseRecord->lookup(Name).begin(); + Path.Decls != Path.Decls.end(); ++Path.Decls) { + if ((*Path.Decls)->isInIdentifierNamespace(IDNS)) return true; } return false; @@ -2256,9 +2256,9 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, AccessSpecifier SubobjectAccess = AS_none; // Check whether the given lookup result contains only static members. - auto HasOnlyStaticMembers = [&](DeclContextLookupResult Result) { - for (NamedDecl *ND : Result) - if (ND->isInIdentifierNamespace(IDNS) && ND->isCXXInstanceMember()) + auto HasOnlyStaticMembers = [&](DeclContext::lookup_iterator Result) { + for (DeclContext::lookup_iterator I = Result, E = I.end(); I != E; ++I) + if ((*I)->isInIdentifierNamespace(IDNS) && (*I)->isCXXInstanceMember()) return false; return true; }; @@ -2267,8 +2267,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // Determine whether two sets of members contain the same members, as // required by C++ [class.member.lookup]p6. - auto HasSameDeclarations = [&](DeclContextLookupResult A, - DeclContextLookupResult B) { + auto HasSameDeclarations = [&](DeclContext::lookup_iterator A, + DeclContext::lookup_iterator B) { using Iterator = DeclContextLookupResult::iterator; using Result = const void *; @@ -2305,7 +2305,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // We'll often find the declarations are in the same order. Handle this // case (and the special case of only one declaration) efficiently. - Iterator AIt = A.begin(), BIt = B.begin(), AEnd = A.end(), BEnd = B.end(); + Iterator AIt = A, BIt = B, AEnd, BEnd; while (true) { Result AResult = Next(AIt, AEnd); Result BResult = Next(BIt, BEnd); @@ -2388,10 +2388,11 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // Lookup in a base class succeeded; return these results. - for (auto *D : Paths.front().Decls) { + for (DeclContext::lookup_iterator I = Paths.front().Decls, E = I.end(); + I != E; ++I) { AccessSpecifier AS = CXXRecordDecl::MergeAccess(SubobjectAccess, - D->getAccess()); - if (NamedDecl *ND = R.getAcceptableDecl(D)) + (*I)->getAccess()); + if (NamedDecl *ND = R.getAcceptableDecl(*I)) R.addDecl(ND, AS); } R.resolveKind(); @@ -2534,7 +2535,7 @@ void Sema::DiagnoseAmbiguousLookup(LookupResult &Result) { << Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths) << LookupRange; - DeclContext::lookup_iterator Found = Paths->front().Decls.begin(); + DeclContext::lookup_iterator Found = Paths->front().Decls; while (isa<CXXMethodDecl>(*Found) && cast<CXXMethodDecl>(*Found)->isStatic()) ++Found; @@ -2552,7 +2553,7 @@ void Sema::DiagnoseAmbiguousLookup(LookupResult &Result) { for (CXXBasePaths::paths_iterator Path = Paths->begin(), PathEnd = Paths->end(); Path != PathEnd; ++Path) { - const NamedDecl *D = Path->Decls.front(); + const NamedDecl *D = *Path->Decls; if (!D->isInIdentifierNamespace(Result.getIdentifierNamespace())) continue; if (DeclsPrinted.insert(D).second) { diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index fdc30fe..db99927 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -112,12 +112,10 @@ CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop, return; // Look for a property with the same name. - DeclContext::lookup_result R = Proto->lookup(Prop->getDeclName()); - for (unsigned I = 0, N = R.size(); I != N; ++I) { - if (ObjCPropertyDecl *ProtoProp = dyn_cast<ObjCPropertyDecl>(R[I])) { - S.DiagnosePropertyMismatch(Prop, ProtoProp, Proto->getIdentifier(), true); - return; - } + if (ObjCPropertyDecl *ProtoProp = + Proto->lookup(Prop->getDeclName()).find_first<ObjCPropertyDecl>()) { + S.DiagnosePropertyMismatch(Prop, ProtoProp, Proto->getIdentifier(), true); + return; } // Check this property against any protocols we inherit. @@ -233,18 +231,13 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, bool FoundInSuper = false; ObjCInterfaceDecl *CurrentInterfaceDecl = IFace; while (ObjCInterfaceDecl *Super = CurrentInterfaceDecl->getSuperClass()) { - DeclContext::lookup_result R = Super->lookup(Res->getDeclName()); - for (unsigned I = 0, N = R.size(); I != N; ++I) { - if (ObjCPropertyDecl *SuperProp = dyn_cast<ObjCPropertyDecl>(R[I])) { - DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier(), false); - FoundInSuper = true; - break; - } - } - if (FoundInSuper) + if (ObjCPropertyDecl *SuperProp = + Super->lookup(Res->getDeclName()).find_first<ObjCPropertyDecl>()) { + DiagnosePropertyMismatch(Res, SuperProp, Super->getIdentifier(), false); + FoundInSuper = true; break; - else - CurrentInterfaceDecl = Super; + } + CurrentInterfaceDecl = Super; } if (FoundInSuper) { @@ -1149,14 +1142,13 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // redeclared 'readwrite', then no warning is to be issued. for (auto *Ext : IDecl->known_extensions()) { DeclContext::lookup_result R = Ext->lookup(property->getDeclName()); - if (!R.empty()) - if (ObjCPropertyDecl *ExtProp = dyn_cast<ObjCPropertyDecl>(R[0])) { - PIkind = ExtProp->getPropertyAttributesAsWritten(); - if (PIkind & ObjCPropertyAttribute::kind_readwrite) { - ReadWriteProperty = true; - break; - } + if (auto *ExtProp = R.find_first<ObjCPropertyDecl>()) { + PIkind = ExtProp->getPropertyAttributesAsWritten(); + if (PIkind & ObjCPropertyAttribute::kind_readwrite) { + ReadWriteProperty = true; + break; } + } } if (!ReadWriteProperty) { diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 8bd812b..578a77a 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -3420,7 +3420,8 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, Instantiation->getTemplateInstantiationPattern(); DeclContext::lookup_result Lookup = ClassPattern->lookup(Field->getDeclName()); - FieldDecl *Pattern = cast<FieldDecl>(Lookup.front()); + FieldDecl *Pattern = Lookup.find_first<FieldDecl>(); + assert(Pattern); InstantiateInClassInitializer(PointOfInstantiation, Field, Pattern, TemplateArgs); } |