forked from OSchip/llvm-project
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
This commit is contained in:
parent
3b8b5d1f22
commit
0cb7e7ca0c
|
@ -195,7 +195,7 @@ const NamedDecl &findDecl(ParsedAST &AST, llvm::StringRef QName) {
|
|||
llvm::StringRef Name) -> const NamedDecl & {
|
||||
auto LookupRes = Scope.lookup(DeclarationName(&Ctx.Idents.get(Name)));
|
||||
assert(!LookupRes.empty() && "Lookup failed");
|
||||
assert(LookupRes.size() == 1 && "Lookup returned multiple results");
|
||||
assert(LookupRes.isSingleResult() && "Lookup returned multiple results");
|
||||
return *LookupRes.front();
|
||||
};
|
||||
|
||||
|
|
|
@ -604,6 +604,9 @@ private:
|
|||
std::unique_ptr<interp::Context> InterpContext;
|
||||
std::unique_ptr<ParentMapContext> ParentMapCtx;
|
||||
|
||||
/// Keeps track of the deallocated DeclListNodes for future reuse.
|
||||
DeclListNode *ListNodeFreeList = nullptr;
|
||||
|
||||
public:
|
||||
IdentifierTable &Idents;
|
||||
SelectorTable &Selectors;
|
||||
|
@ -655,6 +658,24 @@ public:
|
|||
}
|
||||
void Deallocate(void *Ptr) const {}
|
||||
|
||||
/// Allocates a \c DeclListNode or returns one from the \c ListNodeFreeList
|
||||
/// pool.
|
||||
DeclListNode *AllocateDeclListNode(clang::NamedDecl *ND) {
|
||||
if (DeclListNode *Alloc = ListNodeFreeList) {
|
||||
ListNodeFreeList = Alloc->Rest.dyn_cast<DeclListNode*>();
|
||||
Alloc->D = ND;
|
||||
Alloc->Rest = nullptr;
|
||||
return Alloc;
|
||||
}
|
||||
return new (*this) DeclListNode(ND);
|
||||
}
|
||||
/// Deallcates a \c DeclListNode by returning it to the \c ListNodeFreeList
|
||||
/// pool.
|
||||
void DeallocateDeclListNode(DeclListNode *N) {
|
||||
N->Rest = ListNodeFreeList;
|
||||
ListNodeFreeList = N;
|
||||
}
|
||||
|
||||
/// Return the total amount of physical memory allocated for representing
|
||||
/// AST nodes and type information.
|
||||
size_t getASTAllocatedMemory() const {
|
||||
|
|
|
@ -76,9 +76,8 @@ public:
|
|||
|
||||
CXXBasePath() = default;
|
||||
|
||||
/// The set of declarations found inside this base class
|
||||
/// subobject.
|
||||
DeclContext::lookup_result Decls;
|
||||
/// The declarations found inside this base class subobject.
|
||||
DeclContext::lookup_iterator Decls;
|
||||
|
||||
void clear() {
|
||||
SmallVectorImpl<CXXBasePathElement>::clear();
|
||||
|
|
|
@ -579,6 +579,16 @@ public:
|
|||
AnonOrFirstNamespaceAndInline.setInt(Inline);
|
||||
}
|
||||
|
||||
/// Returns true if the inline qualifier for \c Name is redundant.
|
||||
bool isRedundantInlineQualifierFor(DeclarationName Name) const {
|
||||
if (!isInline())
|
||||
return false;
|
||||
auto X = lookup(Name);
|
||||
auto Y = getParent()->lookup(Name);
|
||||
return std::distance(X.begin(), X.end()) ==
|
||||
std::distance(Y.begin(), Y.end());
|
||||
}
|
||||
|
||||
/// Get the original (first) namespace declaration.
|
||||
NamespaceDecl *getOriginalNamespace();
|
||||
|
||||
|
|
|
@ -1220,65 +1220,110 @@ public:
|
|||
|
||||
void print(raw_ostream &OS) const override;
|
||||
};
|
||||
} // namespace clang
|
||||
|
||||
/// The results of name lookup within a DeclContext. This is either a
|
||||
/// single result (with no stable storage) or a collection of results (with
|
||||
/// stable storage provided by the lookup table).
|
||||
// Required to determine the layout of the PointerUnion<NamedDecl*> before
|
||||
// seeing the NamedDecl definition being first used in DeclListNode::operator*.
|
||||
namespace llvm {
|
||||
template <> struct PointerLikeTypeTraits<::clang::NamedDecl *> {
|
||||
static inline void *getAsVoidPointer(::clang::NamedDecl *P) { return P; }
|
||||
static inline ::clang::NamedDecl *getFromVoidPointer(void *P) {
|
||||
return static_cast<::clang::NamedDecl *>(P);
|
||||
}
|
||||
static constexpr int NumLowBitsAvailable = 3;
|
||||
};
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
/// A list storing NamedDecls in the lookup tables.
|
||||
class DeclListNode {
|
||||
friend class ASTContext; // allocate, deallocate nodes.
|
||||
friend class StoredDeclsList;
|
||||
public:
|
||||
using Decls = llvm::PointerUnion<NamedDecl*, DeclListNode*>;
|
||||
class iterator {
|
||||
friend class DeclContextLookupResult;
|
||||
friend class StoredDeclsList;
|
||||
|
||||
Decls Ptr;
|
||||
iterator(Decls Node) : Ptr(Node) { }
|
||||
public:
|
||||
using difference_type = ptrdiff_t;
|
||||
using value_type = NamedDecl*;
|
||||
using pointer = void;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
iterator() = default;
|
||||
|
||||
reference operator*() const {
|
||||
assert(Ptr && "dereferencing end() iterator");
|
||||
if (DeclListNode *CurNode = Ptr.dyn_cast<DeclListNode*>())
|
||||
return CurNode->D;
|
||||
return Ptr.get<NamedDecl*>();
|
||||
}
|
||||
void operator->() const { } // Unsupported.
|
||||
bool operator==(const iterator &X) const { return Ptr == X.Ptr; }
|
||||
bool operator!=(const iterator &X) const { return Ptr != X.Ptr; }
|
||||
inline iterator &operator++() { // ++It
|
||||
assert(!Ptr.isNull() && "Advancing empty iterator");
|
||||
|
||||
if (DeclListNode *CurNode = Ptr.dyn_cast<DeclListNode*>())
|
||||
Ptr = CurNode->Rest;
|
||||
else
|
||||
Ptr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
iterator operator++(int) { // It++
|
||||
iterator temp = *this;
|
||||
++(*this);
|
||||
return temp;
|
||||
}
|
||||
// Enables the pattern for (iterator I =..., E = I.end(); I != E; ++I)
|
||||
iterator end() { return iterator(); }
|
||||
};
|
||||
private:
|
||||
NamedDecl *D = nullptr;
|
||||
Decls Rest = nullptr;
|
||||
DeclListNode(NamedDecl *ND) : D(ND) {}
|
||||
};
|
||||
|
||||
/// The results of name lookup within a DeclContext.
|
||||
class DeclContextLookupResult {
|
||||
using ResultTy = ArrayRef<NamedDecl *>;
|
||||
using Decls = DeclListNode::Decls;
|
||||
|
||||
ResultTy Result;
|
||||
|
||||
// If there is only one lookup result, it would be invalidated by
|
||||
// reallocations of the name table, so store it separately.
|
||||
NamedDecl *Single = nullptr;
|
||||
|
||||
static NamedDecl *const SingleElementDummyList;
|
||||
/// When in collection form, this is what the Data pointer points to.
|
||||
Decls Result;
|
||||
|
||||
public:
|
||||
DeclContextLookupResult() = default;
|
||||
DeclContextLookupResult(ArrayRef<NamedDecl *> Result)
|
||||
: Result(Result) {}
|
||||
DeclContextLookupResult(NamedDecl *Single)
|
||||
: Result(SingleElementDummyList), Single(Single) {}
|
||||
|
||||
class iterator;
|
||||
|
||||
using IteratorBase =
|
||||
llvm::iterator_adaptor_base<iterator, ResultTy::iterator,
|
||||
std::random_access_iterator_tag, NamedDecl *>;
|
||||
|
||||
class iterator : public IteratorBase {
|
||||
value_type SingleElement;
|
||||
|
||||
public:
|
||||
explicit iterator(pointer Pos, value_type Single = nullptr)
|
||||
: IteratorBase(Pos), SingleElement(Single) {}
|
||||
|
||||
reference operator*() const {
|
||||
return SingleElement ? SingleElement : IteratorBase::operator*();
|
||||
}
|
||||
};
|
||||
DeclContextLookupResult(Decls Result) : Result(Result) {}
|
||||
|
||||
using iterator = DeclListNode::iterator;
|
||||
using const_iterator = iterator;
|
||||
using pointer = iterator::pointer;
|
||||
using reference = iterator::reference;
|
||||
|
||||
iterator begin() const { return iterator(Result.begin(), Single); }
|
||||
iterator end() const { return iterator(Result.end(), Single); }
|
||||
iterator begin() { return iterator(Result); }
|
||||
iterator end() { return iterator(); }
|
||||
const_iterator begin() const {
|
||||
return const_cast<DeclContextLookupResult*>(this)->begin();
|
||||
}
|
||||
const_iterator end() const { return iterator(); }
|
||||
|
||||
bool empty() const { return Result.empty(); }
|
||||
pointer data() const { return Single ? &Single : Result.data(); }
|
||||
size_t size() const { return Single ? 1 : Result.size(); }
|
||||
reference front() const { return Single ? Single : Result.front(); }
|
||||
reference back() const { return Single ? Single : Result.back(); }
|
||||
reference operator[](size_t N) const { return Single ? Single : Result[N]; }
|
||||
bool empty() const { return Result.isNull(); }
|
||||
bool isSingleResult() const { return Result.dyn_cast<NamedDecl*>(); }
|
||||
reference front() const { return *begin(); }
|
||||
|
||||
// FIXME: Remove this from the interface
|
||||
DeclContextLookupResult slice(size_t N) const {
|
||||
DeclContextLookupResult Sliced = Result.slice(N);
|
||||
Sliced.Single = Single;
|
||||
return Sliced;
|
||||
// Find the first declaration of the given type in the list. Note that this
|
||||
// is not in general the earliest-declared declaration, and should only be
|
||||
// used when it's not possible for there to be more than one match or where
|
||||
// it doesn't matter which one is found.
|
||||
template<class T> T *find_first() const {
|
||||
for (auto *D : *this)
|
||||
if (T *Decl = dyn_cast<T>(D))
|
||||
return Decl;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#ifndef LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H
|
||||
#define LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H
|
||||
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
|
@ -21,7 +22,6 @@
|
|||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
|
@ -31,231 +31,287 @@ class DependentDiagnostic;
|
|||
|
||||
/// An array of decls optimized for the common case of only containing
|
||||
/// one entry.
|
||||
struct StoredDeclsList {
|
||||
/// When in vector form, this is what the Data pointer points to.
|
||||
using DeclsTy = SmallVector<NamedDecl *, 4>;
|
||||
class StoredDeclsList {
|
||||
using Decls = DeclListNode::Decls;
|
||||
|
||||
/// A collection of declarations, with a flag to indicate if we have
|
||||
/// further external declarations.
|
||||
using DeclsAndHasExternalTy = llvm::PointerIntPair<DeclsTy *, 1, bool>;
|
||||
using DeclsAndHasExternalTy = llvm::PointerIntPair<Decls, 1, bool>;
|
||||
|
||||
/// The stored data, which will be either a pointer to a NamedDecl,
|
||||
/// or a pointer to a vector with a flag to indicate if there are further
|
||||
/// or a pointer to a list with a flag to indicate if there are further
|
||||
/// external declarations.
|
||||
llvm::PointerUnion<NamedDecl *, DeclsAndHasExternalTy> Data;
|
||||
DeclsAndHasExternalTy Data;
|
||||
|
||||
template<typename Fn>
|
||||
void erase_if(Fn ShouldErase) {
|
||||
Decls List = Data.getPointer();
|
||||
if (!List)
|
||||
return;
|
||||
ASTContext &C = getASTContext();
|
||||
DeclListNode::Decls NewHead = nullptr;
|
||||
DeclListNode::Decls *NewLast = nullptr;
|
||||
DeclListNode::Decls *NewTail = &NewHead;
|
||||
while (true) {
|
||||
if (!ShouldErase(*DeclListNode::iterator(List))) {
|
||||
NewLast = NewTail;
|
||||
*NewTail = List;
|
||||
if (auto *Node = List.dyn_cast<DeclListNode*>()) {
|
||||
NewTail = &Node->Rest;
|
||||
List = Node->Rest;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (DeclListNode *N = List.dyn_cast<DeclListNode*>()) {
|
||||
List = N->Rest;
|
||||
C.DeallocateDeclListNode(N);
|
||||
} else {
|
||||
// We're discarding the last declaration in the list. The last node we
|
||||
// want to keep (if any) will be of the form DeclListNode(D, <rest>);
|
||||
// replace it with just D.
|
||||
if (NewLast) {
|
||||
DeclListNode *Node = NewLast->get<DeclListNode*>();
|
||||
*NewLast = Node->D;
|
||||
C.DeallocateDeclListNode(Node);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
Data.setPointer(NewHead);
|
||||
|
||||
assert(llvm::find_if(getLookupResult(), ShouldErase) ==
|
||||
getLookupResult().end() && "Still exists!");
|
||||
}
|
||||
|
||||
void erase(NamedDecl *ND) {
|
||||
erase_if([ND](NamedDecl *D) { return D == ND; });
|
||||
}
|
||||
|
||||
public:
|
||||
StoredDeclsList() = default;
|
||||
|
||||
StoredDeclsList(StoredDeclsList &&RHS) : Data(RHS.Data) {
|
||||
RHS.Data = (NamedDecl *)nullptr;
|
||||
RHS.Data.setPointer(nullptr);
|
||||
RHS.Data.setInt(0);
|
||||
}
|
||||
|
||||
~StoredDeclsList() {
|
||||
// If this is a vector-form, free the vector.
|
||||
if (DeclsTy *Vector = getAsVector())
|
||||
delete Vector;
|
||||
}
|
||||
|
||||
StoredDeclsList &operator=(StoredDeclsList &&RHS) {
|
||||
if (DeclsTy *Vector = getAsVector())
|
||||
delete Vector;
|
||||
Data = RHS.Data;
|
||||
RHS.Data = (NamedDecl *)nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool isNull() const { return Data.isNull(); }
|
||||
|
||||
NamedDecl *getAsDecl() const {
|
||||
return Data.dyn_cast<NamedDecl *>();
|
||||
}
|
||||
|
||||
DeclsAndHasExternalTy getAsVectorAndHasExternal() const {
|
||||
return Data.dyn_cast<DeclsAndHasExternalTy>();
|
||||
}
|
||||
|
||||
DeclsTy *getAsVector() const {
|
||||
return getAsVectorAndHasExternal().getPointer();
|
||||
}
|
||||
|
||||
bool hasExternalDecls() const {
|
||||
return getAsVectorAndHasExternal().getInt();
|
||||
}
|
||||
|
||||
void setHasExternalDecls() {
|
||||
if (DeclsTy *Vec = getAsVector())
|
||||
Data = DeclsAndHasExternalTy(Vec, true);
|
||||
else {
|
||||
DeclsTy *VT = new DeclsTy();
|
||||
if (NamedDecl *OldD = getAsDecl())
|
||||
VT->push_back(OldD);
|
||||
Data = DeclsAndHasExternalTy(VT, true);
|
||||
void MaybeDeallocList() {
|
||||
if (isNull())
|
||||
return;
|
||||
// If this is a list-form, free the list.
|
||||
ASTContext &C = getASTContext();
|
||||
Decls List = Data.getPointer();
|
||||
while (DeclListNode *ToDealloc = List.dyn_cast<DeclListNode *>()) {
|
||||
List = ToDealloc->Rest;
|
||||
C.DeallocateDeclListNode(ToDealloc);
|
||||
}
|
||||
}
|
||||
|
||||
void setOnlyValue(NamedDecl *ND) {
|
||||
assert(!getAsVector() && "Not inline");
|
||||
Data = ND;
|
||||
// Make sure that Data is a plain NamedDecl* so we can use its address
|
||||
// at getLookupResult.
|
||||
assert(*(NamedDecl **)&Data == ND &&
|
||||
"PointerUnion mangles the NamedDecl pointer!");
|
||||
~StoredDeclsList() {
|
||||
MaybeDeallocList();
|
||||
}
|
||||
|
||||
StoredDeclsList &operator=(StoredDeclsList &&RHS) {
|
||||
MaybeDeallocList();
|
||||
|
||||
Data = RHS.Data;
|
||||
RHS.Data.setPointer(nullptr);
|
||||
RHS.Data.setInt(0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool isNull() const { return Data.getPointer().isNull(); }
|
||||
|
||||
ASTContext &getASTContext() {
|
||||
assert(!isNull() && "No ASTContext.");
|
||||
if (NamedDecl *ND = getAsDecl())
|
||||
return ND->getASTContext();
|
||||
return getAsList()->D->getASTContext();
|
||||
}
|
||||
|
||||
DeclsAndHasExternalTy getAsListAndHasExternal() const { return Data; }
|
||||
|
||||
NamedDecl *getAsDecl() const {
|
||||
return getAsListAndHasExternal().getPointer().dyn_cast<NamedDecl *>();
|
||||
}
|
||||
|
||||
DeclListNode *getAsList() const {
|
||||
return getAsListAndHasExternal().getPointer().dyn_cast<DeclListNode*>();
|
||||
}
|
||||
|
||||
bool hasExternalDecls() const {
|
||||
return getAsListAndHasExternal().getInt();
|
||||
}
|
||||
|
||||
void setHasExternalDecls() {
|
||||
Data.setInt(1);
|
||||
}
|
||||
|
||||
void remove(NamedDecl *D) {
|
||||
assert(!isNull() && "removing from empty list");
|
||||
if (NamedDecl *Singleton = getAsDecl()) {
|
||||
assert(Singleton == D && "list is different singleton");
|
||||
(void)Singleton;
|
||||
Data = (NamedDecl *)nullptr;
|
||||
erase(D);
|
||||
}
|
||||
|
||||
/// Remove any declarations which were imported from an external AST source.
|
||||
void removeExternalDecls() {
|
||||
erase_if([](NamedDecl *ND) { return ND->isFromASTFile(); });
|
||||
|
||||
// Don't have any pending external decls any more.
|
||||
Data.setInt(0);
|
||||
}
|
||||
|
||||
void replaceExternalDecls(ArrayRef<NamedDecl*> Decls) {
|
||||
// Remove all declarations that are either external or are replaced with
|
||||
// external declarations.
|
||||
erase_if([Decls](NamedDecl *ND) {
|
||||
if (ND->isFromASTFile())
|
||||
return true;
|
||||
for (NamedDecl *D : Decls)
|
||||
if (D->declarationReplaces(ND, /*IsKnownNewer=*/false))
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
// Don't have any pending external decls any more.
|
||||
Data.setInt(0);
|
||||
|
||||
if (Decls.empty())
|
||||
return;
|
||||
|
||||
// Convert Decls into a list, in order.
|
||||
ASTContext &C = Decls.front()->getASTContext();
|
||||
DeclListNode::Decls DeclsAsList = Decls.back();
|
||||
for (size_t I = Decls.size() - 1; I != 0; --I) {
|
||||
DeclListNode *Node = C.AllocateDeclListNode(Decls[I - 1]);
|
||||
Node->Rest = DeclsAsList;
|
||||
DeclsAsList = Node;
|
||||
}
|
||||
|
||||
DeclListNode::Decls Head = Data.getPointer();
|
||||
if (Head.isNull()) {
|
||||
Data.setPointer(DeclsAsList);
|
||||
return;
|
||||
}
|
||||
|
||||
DeclsTy &Vec = *getAsVector();
|
||||
DeclsTy::iterator I = llvm::find(Vec, D);
|
||||
assert(I != Vec.end() && "list does not contain decl");
|
||||
Vec.erase(I);
|
||||
// Find the end of the existing list.
|
||||
// FIXME: It would be possible to preserve information from erase_if to
|
||||
// avoid this rescan looking for the end of the list.
|
||||
DeclListNode::Decls *Tail = &Head;
|
||||
while (DeclListNode *Node = Tail->dyn_cast<DeclListNode *>())
|
||||
Tail = &Node->Rest;
|
||||
|
||||
assert(llvm::find(Vec, D) == Vec.end() && "list still contains decl");
|
||||
// Append the Decls.
|
||||
DeclListNode *Node = C.AllocateDeclListNode(Tail->get<NamedDecl *>());
|
||||
Node->Rest = DeclsAsList;
|
||||
*Tail = Node;
|
||||
Data.setPointer(Head);
|
||||
}
|
||||
|
||||
/// Remove any declarations which were imported from an external
|
||||
/// AST source.
|
||||
void removeExternalDecls() {
|
||||
/// Return an array of all the decls that this list represents.
|
||||
DeclContext::lookup_result getLookupResult() const {
|
||||
return DeclContext::lookup_result(Data.getPointer());
|
||||
}
|
||||
|
||||
/// If this is a redeclaration of an existing decl, replace the old one with
|
||||
/// D. Otherwise, append D.
|
||||
void addOrReplaceDecl(NamedDecl *D) {
|
||||
const bool IsKnownNewer = true;
|
||||
|
||||
if (isNull()) {
|
||||
// Nothing to do.
|
||||
} else if (NamedDecl *Singleton = getAsDecl()) {
|
||||
if (Singleton->isFromASTFile())
|
||||
*this = StoredDeclsList();
|
||||
} else {
|
||||
DeclsTy &Vec = *getAsVector();
|
||||
Vec.erase(std::remove_if(Vec.begin(), Vec.end(),
|
||||
[](Decl *D) { return D->isFromASTFile(); }),
|
||||
Vec.end());
|
||||
// Don't have any external decls any more.
|
||||
Data = DeclsAndHasExternalTy(&Vec, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// getLookupResult - Return an array of all the decls that this list
|
||||
/// represents.
|
||||
DeclContext::lookup_result getLookupResult() {
|
||||
if (isNull())
|
||||
return DeclContext::lookup_result();
|
||||
|
||||
// If we have a single NamedDecl, return it.
|
||||
if (NamedDecl *ND = getAsDecl()) {
|
||||
assert(!isNull() && "Empty list isn't allowed");
|
||||
|
||||
// Data is a raw pointer to a NamedDecl*, return it.
|
||||
return DeclContext::lookup_result(ND);
|
||||
Data.setPointer(D);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(getAsVector() && "Must have a vector at this point");
|
||||
DeclsTy &Vector = *getAsVector();
|
||||
|
||||
// Otherwise, we have a range result.
|
||||
return DeclContext::lookup_result(Vector);
|
||||
}
|
||||
|
||||
/// HandleRedeclaration - If this is a redeclaration of an existing decl,
|
||||
/// replace the old one with D and return true. Otherwise return false.
|
||||
bool HandleRedeclaration(NamedDecl *D, bool IsKnownNewer) {
|
||||
// Most decls only have one entry in their list, special case it.
|
||||
if (NamedDecl *OldD = getAsDecl()) {
|
||||
if (!D->declarationReplaces(OldD, IsKnownNewer))
|
||||
return false;
|
||||
setOnlyValue(D);
|
||||
return true;
|
||||
if (D->declarationReplaces(OldD, IsKnownNewer)) {
|
||||
Data.setPointer(D);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add D after OldD.
|
||||
ASTContext &C = D->getASTContext();
|
||||
DeclListNode *Node = C.AllocateDeclListNode(OldD);
|
||||
Node->Rest = D;
|
||||
Data.setPointer(Node);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Move the assert before the single decl case when we fix the
|
||||
// duplication coming from the ASTReader reading builtin types.
|
||||
assert(!llvm::is_contained(getLookupResult(), D) && "Already exists!");
|
||||
// Determine if this declaration is actually a redeclaration.
|
||||
DeclsTy &Vec = *getAsVector();
|
||||
for (DeclsTy::iterator OD = Vec.begin(), ODEnd = Vec.end();
|
||||
OD != ODEnd; ++OD) {
|
||||
NamedDecl *OldD = *OD;
|
||||
if (D->declarationReplaces(OldD, IsKnownNewer)) {
|
||||
*OD = D;
|
||||
return true;
|
||||
for (DeclListNode *N = getAsList(); /*return in loop*/;
|
||||
N = N->Rest.dyn_cast<DeclListNode *>()) {
|
||||
if (D->declarationReplaces(N->D, IsKnownNewer)) {
|
||||
N->D = D;
|
||||
return;
|
||||
}
|
||||
if (auto *ND = N->Rest.dyn_cast<NamedDecl *>()) {
|
||||
if (D->declarationReplaces(ND, IsKnownNewer)) {
|
||||
N->Rest = D;
|
||||
return;
|
||||
}
|
||||
|
||||
// Add D after ND.
|
||||
ASTContext &C = D->getASTContext();
|
||||
DeclListNode *Node = C.AllocateDeclListNode(ND);
|
||||
N->Rest = Node;
|
||||
Node->Rest = D;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// AddSubsequentDecl - This is called on the second and later decl when it is
|
||||
/// not a redeclaration to merge it into the appropriate place in our list.
|
||||
void AddSubsequentDecl(NamedDecl *D) {
|
||||
assert(!isNull() && "don't AddSubsequentDecl when we have no decls");
|
||||
|
||||
// If this is the second decl added to the list, convert this to vector
|
||||
// form.
|
||||
if (NamedDecl *OldD = getAsDecl()) {
|
||||
DeclsTy *VT = new DeclsTy();
|
||||
VT->push_back(OldD);
|
||||
Data = DeclsAndHasExternalTy(VT, false);
|
||||
/// Add a declaration to the list without checking if it replaces anything.
|
||||
void prependDeclNoReplace(NamedDecl *D) {
|
||||
if (isNull()) {
|
||||
Data.setPointer(D);
|
||||
return;
|
||||
}
|
||||
|
||||
DeclsTy &Vec = *getAsVector();
|
||||
ASTContext &C = D->getASTContext();
|
||||
DeclListNode *Node = C.AllocateDeclListNode(D);
|
||||
Node->Rest = Data.getPointer();
|
||||
Data.setPointer(Node);
|
||||
}
|
||||
|
||||
// Using directives end up in a special entry which contains only
|
||||
// other using directives, so all this logic is wasted for them.
|
||||
// But avoiding the logic wastes time in the far-more-common case
|
||||
// that we're *not* adding a new using directive.
|
||||
LLVM_DUMP_METHOD void dump() const {
|
||||
Decls D = Data.getPointer();
|
||||
if (!D) {
|
||||
llvm::errs() << "<null>\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// Tag declarations always go at the end of the list so that an
|
||||
// iterator which points at the first tag will start a span of
|
||||
// decls that only contains tags.
|
||||
if (D->hasTagIdentifierNamespace())
|
||||
Vec.push_back(D);
|
||||
|
||||
// Resolved using declarations go at the front of the list so that
|
||||
// they won't show up in other lookup results. Unresolved using
|
||||
// declarations (which are always in IDNS_Using | IDNS_Ordinary)
|
||||
// follow that so that the using declarations will be contiguous.
|
||||
else if (D->getIdentifierNamespace() & Decl::IDNS_Using) {
|
||||
DeclsTy::iterator I = Vec.begin();
|
||||
if (D->getIdentifierNamespace() != Decl::IDNS_Using) {
|
||||
while (I != Vec.end() &&
|
||||
(*I)->getIdentifierNamespace() == Decl::IDNS_Using)
|
||||
++I;
|
||||
while (true) {
|
||||
if (auto *Node = D.dyn_cast<DeclListNode*>()) {
|
||||
llvm::errs() << '[' << Node->D << "] -> ";
|
||||
D = Node->Rest;
|
||||
} else {
|
||||
llvm::errs() << '[' << D.get<NamedDecl*>() << "]\n";
|
||||
return;
|
||||
}
|
||||
Vec.insert(I, D);
|
||||
|
||||
// All other declarations go at the end of the list, but before any
|
||||
// tag declarations. But we can be clever about tag declarations
|
||||
// because there can only ever be one in a scope.
|
||||
} else if (!Vec.empty() && Vec.back()->hasTagIdentifierNamespace()) {
|
||||
NamedDecl *TagD = Vec.back();
|
||||
Vec.back() = D;
|
||||
Vec.push_back(TagD);
|
||||
} else
|
||||
Vec.push_back(D);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class StoredDeclsMap
|
||||
: public llvm::SmallDenseMap<DeclarationName, StoredDeclsList, 4> {
|
||||
public:
|
||||
static void DestroyAll(StoredDeclsMap *Map, bool Dependent);
|
||||
|
||||
private:
|
||||
friend class ASTContext; // walks the chain deleting these
|
||||
friend class DeclContext;
|
||||
|
||||
llvm::PointerIntPair<StoredDeclsMap*, 1> Previous;
|
||||
public:
|
||||
static void DestroyAll(StoredDeclsMap *Map, bool Dependent);
|
||||
};
|
||||
|
||||
class DependentStoredDeclsMap : public StoredDeclsMap {
|
||||
public:
|
||||
DependentStoredDeclsMap() = default;
|
||||
|
||||
private:
|
||||
friend class DeclContext; // iterates over diagnostics
|
||||
friend class DependentDiagnostic;
|
||||
|
||||
DependentDiagnostic *FirstDiagnostic = nullptr;
|
||||
public:
|
||||
DependentStoredDeclsMap() = default;
|
||||
};
|
||||
|
||||
} // namespace clang
|
||||
|
|
|
@ -84,7 +84,7 @@ class RecordDecl;
|
|||
class Sema;
|
||||
class SourceManager;
|
||||
class Stmt;
|
||||
struct StoredDeclsList;
|
||||
class StoredDeclsList;
|
||||
class SwitchCase;
|
||||
class TemplateParameterList;
|
||||
class Token;
|
||||
|
|
|
@ -613,7 +613,7 @@ ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
|
|||
continue;
|
||||
HasAtleastOneRequiredProperty = true;
|
||||
DeclContext::lookup_result R = IDecl->lookup(Property->getDeclName());
|
||||
if (R.size() == 0) {
|
||||
if (R.empty()) {
|
||||
// Relax the rule and look into class's implementation for a synthesize
|
||||
// or dynamic declaration. Class is implementing a property coming from
|
||||
// another protocol. This still makes the target protocol as conforming.
|
||||
|
@ -621,14 +621,12 @@ ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
|
|||
Property->getDeclName().getAsIdentifierInfo(),
|
||||
Property->getQueryKind()))
|
||||
return false;
|
||||
}
|
||||
else if (ObjCPropertyDecl *ClassProperty = dyn_cast<ObjCPropertyDecl>(R[0])) {
|
||||
if ((ClassProperty->getPropertyAttributes()
|
||||
!= Property->getPropertyAttributes()) ||
|
||||
!Ctx.hasSameType(ClassProperty->getType(), Property->getType()))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
} else if (auto *ClassProperty = R.find_first<ObjCPropertyDecl>()) {
|
||||
if ((ClassProperty->getPropertyAttributes() !=
|
||||
Property->getPropertyAttributes()) ||
|
||||
!Ctx.hasSameType(ClassProperty->getType(), Property->getType()))
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -645,12 +643,12 @@ ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
|
|||
if (MD->getImplementationControl() == ObjCMethodDecl::Optional)
|
||||
continue;
|
||||
DeclContext::lookup_result R = ImpDecl->lookup(MD->getDeclName());
|
||||
if (R.size() == 0)
|
||||
if (R.empty())
|
||||
return false;
|
||||
bool match = false;
|
||||
HasAtleastOneRequiredMethod = true;
|
||||
for (unsigned I = 0, N = R.size(); I != N; ++I)
|
||||
if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(R[0]))
|
||||
for (NamedDecl *ND : R)
|
||||
if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(ND))
|
||||
if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) {
|
||||
match = true;
|
||||
break;
|
||||
|
|
|
@ -10892,6 +10892,9 @@ void ASTContext::forEachMultiversionedFunctionVersion(
|
|||
assert(FD->isMultiVersion() && "Only valid for multiversioned functions");
|
||||
llvm::SmallDenseSet<const FunctionDecl*, 4> SeenDecls;
|
||||
FD = FD->getMostRecentDecl();
|
||||
// FIXME: The order of traversal here matters and depends on the order of
|
||||
// lookup results, which happens to be (mostly) oldest-to-newest, but we
|
||||
// shouldn't rely on that.
|
||||
for (auto *CurDecl :
|
||||
FD->getDeclContext()->getRedeclContext()->lookup(FD->getDeclName())) {
|
||||
FunctionDecl *CurFD = CurDecl->getAsFunction()->getMostRecentDecl();
|
||||
|
|
|
@ -386,9 +386,9 @@ static bool isOrdinaryMember(const NamedDecl *ND) {
|
|||
|
||||
static bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path,
|
||||
DeclarationName Name) {
|
||||
Path.Decls = RD->lookup(Name);
|
||||
for (NamedDecl *ND : Path.Decls)
|
||||
if (isOrdinaryMember(ND))
|
||||
Path.Decls = RD->lookup(Name).begin();
|
||||
for (DeclContext::lookup_iterator I = Path.Decls, E = I.end(); I != E; ++I)
|
||||
if (isOrdinaryMember(*I))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -453,9 +453,10 @@ std::vector<const NamedDecl *> CXXRecordDecl::lookupDependentName(
|
|||
},
|
||||
Paths, /*LookupInDependent=*/true))
|
||||
return Results;
|
||||
for (const NamedDecl *ND : Paths.front().Decls) {
|
||||
if (isOrdinaryMember(ND) && Filter(ND))
|
||||
Results.push_back(ND);
|
||||
for (DeclContext::lookup_iterator I = Paths.front().Decls, E = I.end();
|
||||
I != E; ++I) {
|
||||
if (isOrdinaryMember(*I) && Filter(*I))
|
||||
Results.push_back(*I);
|
||||
}
|
||||
return Results;
|
||||
}
|
||||
|
|
|
@ -1612,8 +1612,7 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS,
|
|||
|
||||
// Suppress inline namespace if it doesn't make the result ambiguous.
|
||||
if (P.SuppressInlineNamespace && Ctx->isInlineNamespace() && NameInScope &&
|
||||
Ctx->lookup(NameInScope).size() ==
|
||||
Ctx->getParent()->lookup(NameInScope).size())
|
||||
cast<NamespaceDecl>(Ctx)->isRedundantInlineQualifierFor(NameInScope))
|
||||
continue;
|
||||
|
||||
// Skip non-named contexts such as linkage specifications and ExportDecls.
|
||||
|
|
|
@ -1394,39 +1394,7 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
|
|||
DC->reconcileExternalVisibleStorage();
|
||||
|
||||
StoredDeclsList &List = (*Map)[Name];
|
||||
|
||||
// Clear out any old external visible declarations, to avoid quadratic
|
||||
// performance in the redeclaration checks below.
|
||||
List.removeExternalDecls();
|
||||
|
||||
if (!List.isNull()) {
|
||||
// We have both existing declarations and new declarations for this name.
|
||||
// Some of the declarations may simply replace existing ones. Handle those
|
||||
// first.
|
||||
llvm::SmallVector<unsigned, 8> Skip;
|
||||
for (unsigned I = 0, N = Decls.size(); I != N; ++I)
|
||||
if (List.HandleRedeclaration(Decls[I], /*IsKnownNewer*/false))
|
||||
Skip.push_back(I);
|
||||
Skip.push_back(Decls.size());
|
||||
|
||||
// Add in any new declarations.
|
||||
unsigned SkipPos = 0;
|
||||
for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
|
||||
if (I == Skip[SkipPos])
|
||||
++SkipPos;
|
||||
else
|
||||
List.AddSubsequentDecl(Decls[I]);
|
||||
}
|
||||
} else {
|
||||
// Convert the array to a StoredDeclsList.
|
||||
for (auto *D : Decls) {
|
||||
if (List.isNull())
|
||||
List.setOnlyValue(D);
|
||||
else
|
||||
List.AddSubsequentDecl(D);
|
||||
}
|
||||
}
|
||||
|
||||
List.replaceExternalDecls(Decls);
|
||||
return List.getLookupResult();
|
||||
}
|
||||
|
||||
|
@ -1538,10 +1506,7 @@ void DeclContext::removeDecl(Decl *D) {
|
|||
if (Map) {
|
||||
StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName());
|
||||
assert(Pos != Map->end() && "no lookup entry for decl");
|
||||
// Remove the decl only if it is contained.
|
||||
StoredDeclsList::DeclsTy *Vec = Pos->second.getAsVector();
|
||||
if ((Vec && is_contained(*Vec, ND)) || Pos->second.getAsDecl() == ND)
|
||||
Pos->second.remove(ND);
|
||||
Pos->second.remove(ND);
|
||||
}
|
||||
} while (DC->isTransparentContext() && (DC = DC->getParent()));
|
||||
}
|
||||
|
@ -1658,8 +1623,6 @@ void DeclContext::buildLookupImpl(DeclContext *DCtx, bool Internal) {
|
|||
}
|
||||
}
|
||||
|
||||
NamedDecl *const DeclContextLookupResult::SingleElementDummyList = nullptr;
|
||||
|
||||
DeclContext::lookup_result
|
||||
DeclContext::lookup(DeclarationName Name) const {
|
||||
assert(getDeclKind() != Decl::LinkageSpec &&
|
||||
|
@ -1935,23 +1898,11 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) {
|
|||
// In this case, we never try to replace an existing declaration; we'll
|
||||
// handle that when we finalize the list of declarations for this name.
|
||||
DeclNameEntries.setHasExternalDecls();
|
||||
DeclNameEntries.AddSubsequentDecl(D);
|
||||
DeclNameEntries.prependDeclNoReplace(D);
|
||||
return;
|
||||
}
|
||||
|
||||
if (DeclNameEntries.isNull()) {
|
||||
DeclNameEntries.setOnlyValue(D);
|
||||
return;
|
||||
}
|
||||
|
||||
if (DeclNameEntries.HandleRedeclaration(D, /*IsKnownNewer*/!Internal)) {
|
||||
// This declaration has replaced an existing one for which
|
||||
// declarationReplaces returns true.
|
||||
return;
|
||||
}
|
||||
|
||||
// Put this declaration into the appropriate slot.
|
||||
DeclNameEntries.AddSubsequentDecl(D);
|
||||
DeclNameEntries.addOrReplaceDecl(D);
|
||||
}
|
||||
|
||||
UsingDirectiveDecl *DeclContext::udir_iterator::operator*() const {
|
||||
|
|
|
@ -64,24 +64,24 @@ LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC,
|
|||
Source<DeclarationName> SourceName = *SourceNameOrErr;
|
||||
DeclContext::lookup_result SearchResult =
|
||||
SourceParentDC.get()->lookup(SourceName.get());
|
||||
size_t SearchResultSize = SearchResult.size();
|
||||
if (SearchResultSize == 0 || SearchResultSize > 1) {
|
||||
// There are two cases here. First, we might not find the name.
|
||||
// We might also find multiple copies, in which case we have no
|
||||
// guarantee that the one we wanted is the one we pick. (E.g.,
|
||||
// if we have two specializations of the same template it is
|
||||
// very hard to determine which is the one you want.)
|
||||
//
|
||||
// The Origins map fixes this problem by allowing the origin to be
|
||||
// explicitly recorded, so we trigger that recording by returning
|
||||
// nothing (rather than a possibly-inaccurate guess) here.
|
||||
return nullptr;
|
||||
} else {
|
||||
NamedDecl *SearchResultDecl = SearchResult[0];
|
||||
|
||||
// There are two cases here. First, we might not find the name.
|
||||
// We might also find multiple copies, in which case we have no
|
||||
// guarantee that the one we wanted is the one we pick. (E.g.,
|
||||
// if we have two specializations of the same template it is
|
||||
// very hard to determine which is the one you want.)
|
||||
//
|
||||
// The Origins map fixes this problem by allowing the origin to be
|
||||
// explicitly recorded, so we trigger that recording by returning
|
||||
// nothing (rather than a possibly-inaccurate guess) here.
|
||||
if (SearchResult.isSingleResult()) {
|
||||
NamedDecl *SearchResultDecl = SearchResult.front();
|
||||
if (isa<DeclContext>(SearchResultDecl) &&
|
||||
SearchResultDecl->getKind() == DC->getDeclKind())
|
||||
return cast<DeclContext>(SearchResultDecl)->getPrimaryContext();
|
||||
return nullptr; // This type of lookup is unsupported
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1235,8 +1235,7 @@ void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS,
|
|||
// Only suppress an inline namespace if the name has the same lookup
|
||||
// results in the enclosing namespace.
|
||||
if (Policy.SuppressInlineNamespace && NS->isInline() && NameInScope &&
|
||||
DC->getParent()->lookup(NameInScope).size() ==
|
||||
DC->lookup(NameInScope).size())
|
||||
NS->isRedundantInlineQualifierFor(NameInScope))
|
||||
return AppendScope(DC->getParent(), OS, NameInScope);
|
||||
|
||||
AppendScope(DC->getParent(), OS, NS->getDeclName());
|
||||
|
|
|
@ -4673,7 +4673,6 @@ public:
|
|||
|
||||
struct MultiVersionResolverOption {
|
||||
llvm::Function *Function;
|
||||
FunctionDecl *FD;
|
||||
struct Conds {
|
||||
StringRef Architecture;
|
||||
llvm::SmallVector<StringRef, 8> Features;
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "clang/Sema/MultiplexExternalSemaSource.h"
|
||||
#include "clang/AST/DeclContextInternals.h"
|
||||
#include "clang/Sema/Lookup.h"
|
||||
|
||||
using namespace clang;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -7649,9 +7649,10 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
|
|||
|
||||
// Load the list of declarations.
|
||||
SmallVector<NamedDecl *, 64> Decls;
|
||||
llvm::SmallPtrSet<NamedDecl *, 8> Found;
|
||||
for (DeclID ID : It->second.Table.find(Name)) {
|
||||
NamedDecl *ND = cast<NamedDecl>(GetDecl(ID));
|
||||
if (ND->getDeclName() == Name)
|
||||
if (ND->getDeclName() == Name && Found.insert(ND).second)
|
||||
Decls.push_back(ND);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "ASTCommon.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/DeclContextInternals.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/DeclVisitor.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
|
|
|
@ -842,7 +842,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
|
|||
llvm::Optional<QualType> operator()(StringRef Name) {
|
||||
IdentifierInfo &II = ACtx.Idents.get(Name);
|
||||
auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
|
||||
if (LookupRes.size() == 0)
|
||||
if (LookupRes.empty())
|
||||
return None;
|
||||
|
||||
// Prioritze typedef declarations.
|
||||
|
@ -994,7 +994,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
|
|||
return false;
|
||||
IdentifierInfo &II = ACtx.Idents.get(Name);
|
||||
auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
|
||||
if (LookupRes.size() == 0)
|
||||
if (LookupRes.empty())
|
||||
return false;
|
||||
for (Decl *D : LookupRes) {
|
||||
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// RUN: %clang_cc1 -std=c++2a -include %s %s -ast-print -verify | FileCheck %s
|
||||
//
|
||||
// RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t-cxx2a
|
||||
// RUN: %clang_cc1 -std=c++2a -DUSE_PCH -include-pch %t-cxx2a %s -ast-print -verify | FileCheck %s
|
||||
// RUN: %clang_cc1 -std=c++2a -include-pch %t-cxx2a %s -ast-print -verify | FileCheck %s
|
||||
|
||||
// RUN: %clang_cc1 -std=c++2a -emit-pch -fpch-instantiate-templates %s -o %t-cxx2a
|
||||
// RUN: %clang_cc1 -std=c++2a -DUSE_PCH -include-pch %t-cxx2a %s -ast-print -verify | FileCheck %s
|
||||
// RUN: %clang_cc1 -std=c++2a -include-pch %t-cxx2a %s -ast-print -verify | FileCheck %s
|
||||
|
||||
#ifndef USE_PCH
|
||||
namespace inheriting_constructor {
|
||||
|
@ -125,3 +127,5 @@ A a1 = { 0 };
|
|||
#endif
|
||||
|
||||
}
|
||||
|
||||
#define USE_PCH
|
||||
|
|
|
@ -1030,7 +1030,7 @@ long long clang_Type_getOffsetOf(CXType PT, const char *S) {
|
|||
// and we would return InvalidFieldName instead of Incomplete.
|
||||
// But this erroneous results does protects again a hidden assertion failure
|
||||
// in the RecordLayoutBuilder
|
||||
if (Res.size() != 1)
|
||||
if (!Res.isSingleResult())
|
||||
return CXTypeLayoutError_InvalidFieldName;
|
||||
if (const FieldDecl *FD = dyn_cast<FieldDecl>(Res.front()))
|
||||
return Ctx.getFieldOffset(FD);
|
||||
|
|
|
@ -2561,9 +2561,9 @@ TEST_P(ImportFriendFunctions, Lookup) {
|
|||
auto FromName = FromD->getDeclName();
|
||||
auto *Class = FirstDeclMatcher<CXXRecordDecl>().match(FromTU, ClassPattern);
|
||||
auto LookupRes = Class->noload_lookup(FromName);
|
||||
ASSERT_EQ(LookupRes.size(), 0u);
|
||||
ASSERT_TRUE(LookupRes.empty());
|
||||
LookupRes = FromTU->noload_lookup(FromName);
|
||||
ASSERT_EQ(LookupRes.size(), 1u);
|
||||
ASSERT_TRUE(LookupRes.isSingleResult());
|
||||
}
|
||||
|
||||
auto *ToD = cast<FunctionDecl>(Import(FromD, Lang_CXX03));
|
||||
|
@ -2572,9 +2572,9 @@ TEST_P(ImportFriendFunctions, Lookup) {
|
|||
TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
|
||||
auto *Class = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, ClassPattern);
|
||||
auto LookupRes = Class->noload_lookup(ToName);
|
||||
EXPECT_EQ(LookupRes.size(), 0u);
|
||||
EXPECT_TRUE(LookupRes.empty());
|
||||
LookupRes = ToTU->noload_lookup(ToName);
|
||||
EXPECT_EQ(LookupRes.size(), 1u);
|
||||
EXPECT_TRUE(LookupRes.isSingleResult());
|
||||
|
||||
EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, FunctionPattern), 1u);
|
||||
auto *To0 = FirstDeclMatcher<FunctionDecl>().match(ToTU, FunctionPattern);
|
||||
|
@ -2608,9 +2608,9 @@ TEST_P(ImportFriendFunctions, LookupWithProtoAfter) {
|
|||
auto *FromClass =
|
||||
FirstDeclMatcher<CXXRecordDecl>().match(FromTU, ClassPattern);
|
||||
auto LookupRes = FromClass->noload_lookup(FromName);
|
||||
ASSERT_EQ(LookupRes.size(), 0u);
|
||||
ASSERT_TRUE(LookupRes.empty());
|
||||
LookupRes = FromTU->noload_lookup(FromName);
|
||||
ASSERT_EQ(LookupRes.size(), 1u);
|
||||
ASSERT_TRUE(LookupRes.isSingleResult());
|
||||
|
||||
auto *ToFriend = cast<FunctionDecl>(Import(FromFriend, Lang_CXX03));
|
||||
auto ToName = ToFriend->getDeclName();
|
||||
|
@ -2618,10 +2618,10 @@ TEST_P(ImportFriendFunctions, LookupWithProtoAfter) {
|
|||
TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
|
||||
auto *ToClass = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, ClassPattern);
|
||||
LookupRes = ToClass->noload_lookup(ToName);
|
||||
EXPECT_EQ(LookupRes.size(), 0u);
|
||||
EXPECT_TRUE(LookupRes.empty());
|
||||
LookupRes = ToTU->noload_lookup(ToName);
|
||||
// Test is disabled because this result is 2.
|
||||
EXPECT_EQ(LookupRes.size(), 1u);
|
||||
EXPECT_TRUE(LookupRes.isSingleResult());
|
||||
|
||||
ASSERT_EQ(DeclCounter<FunctionDecl>().match(ToTU, FunctionPattern), 2u);
|
||||
ToFriend = FirstDeclMatcher<FunctionDecl>().match(ToTU, FunctionPattern);
|
||||
|
@ -2652,9 +2652,9 @@ TEST_P(ImportFriendFunctions, LookupWithProtoBefore) {
|
|||
auto *FromClass =
|
||||
FirstDeclMatcher<CXXRecordDecl>().match(FromTU, ClassPattern);
|
||||
auto LookupRes = FromClass->noload_lookup(FromName);
|
||||
ASSERT_EQ(LookupRes.size(), 0u);
|
||||
ASSERT_TRUE(LookupRes.empty());
|
||||
LookupRes = FromTU->noload_lookup(FromName);
|
||||
ASSERT_EQ(LookupRes.size(), 1u);
|
||||
ASSERT_TRUE(LookupRes.isSingleResult());
|
||||
|
||||
auto *ToNormal = cast<FunctionDecl>(Import(FromNormal, Lang_CXX03));
|
||||
auto ToName = ToNormal->getDeclName();
|
||||
|
@ -2662,9 +2662,9 @@ TEST_P(ImportFriendFunctions, LookupWithProtoBefore) {
|
|||
|
||||
auto *ToClass = FirstDeclMatcher<CXXRecordDecl>().match(ToTU, ClassPattern);
|
||||
LookupRes = ToClass->noload_lookup(ToName);
|
||||
EXPECT_EQ(LookupRes.size(), 0u);
|
||||
EXPECT_TRUE(LookupRes.empty());
|
||||
LookupRes = ToTU->noload_lookup(ToName);
|
||||
EXPECT_EQ(LookupRes.size(), 1u);
|
||||
EXPECT_TRUE(LookupRes.isSingleResult());
|
||||
|
||||
EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, FunctionPattern), 2u);
|
||||
ToNormal = FirstDeclMatcher<FunctionDecl>().match(ToTU, FunctionPattern);
|
||||
|
@ -2694,9 +2694,9 @@ TEST_P(ImportFriendFunctions, ImportFriendChangesLookup) {
|
|||
ASSERT_FALSE(FromFriendF->isInIdentifierNamespace(Decl::IDNS_Ordinary));
|
||||
ASSERT_TRUE(FromFriendF->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
|
||||
auto LookupRes = FromNormalTU->noload_lookup(FromNormalName);
|
||||
ASSERT_EQ(LookupRes.size(), 1u);
|
||||
ASSERT_TRUE(LookupRes.isSingleResult());
|
||||
LookupRes = FromFriendTU->noload_lookup(FromFriendName);
|
||||
ASSERT_EQ(LookupRes.size(), 1u);
|
||||
ASSERT_TRUE(LookupRes.isSingleResult());
|
||||
|
||||
auto *ToNormalF = cast<FunctionDecl>(Import(FromNormalF, Lang_CXX03));
|
||||
TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl();
|
||||
|
@ -2704,12 +2704,12 @@ TEST_P(ImportFriendFunctions, ImportFriendChangesLookup) {
|
|||
EXPECT_TRUE(ToNormalF->isInIdentifierNamespace(Decl::IDNS_Ordinary));
|
||||
EXPECT_FALSE(ToNormalF->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend));
|
||||
LookupRes = ToTU->noload_lookup(ToName);
|
||||
EXPECT_EQ(LookupRes.size(), 1u);
|
||||
EXPECT_TRUE(LookupRes.isSingleResult());
|
||||
EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 1u);
|
||||
|
||||
auto *ToFriendF = cast<FunctionDecl>(Import(FromFriendF, Lang_CXX03));
|
||||
LookupRes = ToTU->noload_lookup(ToName);
|
||||
EXPECT_EQ(LookupRes.size(), 1u);
|
||||
EXPECT_TRUE(LookupRes.isSingleResult());
|
||||
EXPECT_EQ(DeclCounter<FunctionDecl>().match(ToTU, Pattern), 2u);
|
||||
|
||||
EXPECT_TRUE(ToNormalF->isInIdentifierNamespace(Decl::IDNS_Ordinary));
|
||||
|
@ -4031,11 +4031,11 @@ TEST_P(DeclContextTest,
|
|||
|
||||
ASSERT_TRUE(L.getAsDecl());
|
||||
// Simulate the private function DeclContext::reconcileExternalVisibleStorage.
|
||||
// The point here is to have a Vec with only one element, which is not the
|
||||
// one we are going to delete from the DC later.
|
||||
// We do not have a list with one element.
|
||||
L.setHasExternalDecls();
|
||||
ASSERT_TRUE(L.getAsVector());
|
||||
ASSERT_EQ(1u, L.getAsVector()->size());
|
||||
ASSERT_FALSE(L.getAsList());
|
||||
auto Results = L.getLookupResult();
|
||||
ASSERT_EQ(1u, std::distance(Results.begin(), Results.end()));
|
||||
|
||||
// This asserts in the old implementation.
|
||||
DC->removeDecl(A0);
|
||||
|
|
|
@ -59,7 +59,7 @@ public:
|
|||
clang::DeclContext::lookup_result result =
|
||||
non_const_interface_decl->lookup(name);
|
||||
|
||||
return (result.size() != 0);
|
||||
return (!result.empty());
|
||||
} while (false);
|
||||
|
||||
SetNoExternalVisibleDeclsForName(decl_ctx, name);
|
||||
|
@ -555,7 +555,7 @@ uint32_t AppleObjCDeclVendor::FindDecls(ConstString name, bool append,
|
|||
|
||||
if (!lookup_result.empty()) {
|
||||
if (clang::ObjCInterfaceDecl *result_iface_decl =
|
||||
llvm::dyn_cast<clang::ObjCInterfaceDecl>(lookup_result[0])) {
|
||||
llvm::dyn_cast<clang::ObjCInterfaceDecl>(*lookup_result.begin())) {
|
||||
if (log) {
|
||||
clang::QualType result_iface_type =
|
||||
ast_ctx.getObjCInterfaceType(result_iface_decl);
|
||||
|
|
|
@ -326,7 +326,7 @@ GetDeclFromContextByName(const clang::ASTContext &ast,
|
|||
if (result.empty())
|
||||
return nullptr;
|
||||
|
||||
return result[0];
|
||||
return *result.begin();
|
||||
}
|
||||
|
||||
static bool IsAnonymousNamespaceName(llvm::StringRef name) {
|
||||
|
|
|
@ -163,7 +163,6 @@ void addOverridesForMethod(clang::CXXMethodDecl *decl) {
|
|||
if (name.getNameKind() == clang::DeclarationName::CXXDestructorName)
|
||||
if (auto *baseDtorDecl = base_record->getDestructor()) {
|
||||
if (baseDtorDecl->isVirtual()) {
|
||||
path.Decls = baseDtorDecl;
|
||||
decls.push_back(baseDtorDecl);
|
||||
return true;
|
||||
} else
|
||||
|
@ -171,12 +170,11 @@ void addOverridesForMethod(clang::CXXMethodDecl *decl) {
|
|||
}
|
||||
|
||||
// Otherwise, search for name in the base class.
|
||||
for (path.Decls = base_record->lookup(name); !path.Decls.empty();
|
||||
path.Decls = path.Decls.slice(1)) {
|
||||
for (path.Decls = base_record->lookup(name).begin();
|
||||
path.Decls != path.Decls.end(); ++path.Decls) {
|
||||
if (auto *method_decl =
|
||||
llvm::dyn_cast<clang::CXXMethodDecl>(path.Decls.front()))
|
||||
llvm::dyn_cast<clang::CXXMethodDecl>(*path.Decls))
|
||||
if (method_decl->isVirtual() && !isOverload(decl, method_decl)) {
|
||||
path.Decls = method_decl;
|
||||
decls.push_back(method_decl);
|
||||
return true;
|
||||
}
|
||||
|
@ -6605,10 +6603,11 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName(
|
|||
if (cxx_record_decl->lookupInBases(
|
||||
[decl_name](const clang::CXXBaseSpecifier *specifier,
|
||||
clang::CXXBasePath &path) {
|
||||
path.Decls =
|
||||
specifier->getType()->getAsCXXRecordDecl()->lookup(
|
||||
decl_name);
|
||||
return !path.Decls.empty();
|
||||
CXXRecordDecl *record =
|
||||
specifier->getType()->getAsCXXRecordDecl();
|
||||
auto r = record->lookup(decl_name);
|
||||
path.Decls = r.begin();
|
||||
return !r.empty();
|
||||
},
|
||||
paths)) {
|
||||
clang::CXXBasePaths::const_paths_iterator path,
|
||||
|
@ -6631,9 +6630,10 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName(
|
|||
->getDecl());
|
||||
}
|
||||
}
|
||||
for (clang::NamedDecl *path_decl : path->Decls) {
|
||||
for (clang::DeclContext::lookup_iterator I = path->Decls, E;
|
||||
I != E; ++I) {
|
||||
child_idx = GetIndexForRecordChild(
|
||||
parent_record_decl, path_decl, omit_empty_base_classes);
|
||||
parent_record_decl, *I, omit_empty_base_classes);
|
||||
if (child_idx == UINT32_MAX) {
|
||||
child_indexes.clear();
|
||||
return 0;
|
||||
|
|
|
@ -265,7 +265,7 @@ public:
|
|||
clang::DeclContext::lookup_result result = decl_context->lookup(myName);
|
||||
|
||||
if (!result.empty()) {
|
||||
clang::NamedDecl *named_decl = result[0];
|
||||
clang::NamedDecl *named_decl = *result.begin();
|
||||
if (const RecordDeclType *record_decl =
|
||||
llvm::dyn_cast<RecordDeclType>(named_decl))
|
||||
compiler_type.SetCompilerType(
|
||||
|
|
Loading…
Reference in New Issue