forked from OSchip/llvm-project
Change ADL to produce lookup results in a deterministic order. This fixes some
rare issues with nondeterministic diagnostic order, and some very common issues with nondeterministic module builds. llvm-svn: 264323
This commit is contained in:
parent
3db3f6d83a
commit
6642bb3337
|
@ -769,7 +769,13 @@ public:
|
|||
class ADLResult {
|
||||
private:
|
||||
/// A map from canonical decls to the 'most recent' decl.
|
||||
llvm::DenseMap<NamedDecl*, NamedDecl*> Decls;
|
||||
llvm::MapVector<NamedDecl*, NamedDecl*> Decls;
|
||||
|
||||
struct select_second {
|
||||
NamedDecl *operator()(std::pair<NamedDecl*, NamedDecl*> P) const {
|
||||
return P.second;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
/// Adds a new ADL candidate to this map.
|
||||
|
@ -780,23 +786,11 @@ public:
|
|||
Decls.erase(cast<NamedDecl>(D->getCanonicalDecl()));
|
||||
}
|
||||
|
||||
class iterator
|
||||
: public llvm::iterator_adaptor_base<
|
||||
iterator, llvm::DenseMap<NamedDecl *, NamedDecl *>::iterator,
|
||||
std::forward_iterator_tag, NamedDecl *> {
|
||||
friend class ADLResult;
|
||||
typedef llvm::mapped_iterator<decltype(Decls)::iterator, select_second>
|
||||
iterator;
|
||||
|
||||
iterator(llvm::DenseMap<NamedDecl *, NamedDecl *>::iterator Iter)
|
||||
: iterator_adaptor_base(std::move(Iter)) {}
|
||||
|
||||
public:
|
||||
iterator() {}
|
||||
|
||||
value_type operator*() const { return I->second; }
|
||||
};
|
||||
|
||||
iterator begin() { return iterator(Decls.begin()); }
|
||||
iterator end() { return iterator(Decls.end()); }
|
||||
iterator begin() { return iterator(Decls.begin(), select_second()); }
|
||||
iterator end() { return iterator(Decls.end(), select_second()); }
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -2385,8 +2385,8 @@ public:
|
|||
|
||||
// Members have to be NamespaceDecl* or TranslationUnitDecl*.
|
||||
// TODO: make this is a typesafe union.
|
||||
typedef llvm::SmallPtrSet<DeclContext *, 16> AssociatedNamespaceSet;
|
||||
typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet;
|
||||
typedef llvm::SmallSetVector<DeclContext *, 16> AssociatedNamespaceSet;
|
||||
typedef llvm::SmallSetVector<CXXRecordDecl *, 16> AssociatedClassSet;
|
||||
|
||||
void AddOverloadCandidate(FunctionDecl *Function,
|
||||
DeclAccessPair FoundDecl,
|
||||
|
|
|
@ -2446,7 +2446,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
|
|||
// FIXME: That's not correct, we may have added this class only because it
|
||||
// was the enclosing class of another class, and in that case we won't have
|
||||
// added its base classes yet.
|
||||
if (!Result.Classes.insert(Class).second)
|
||||
if (!Result.Classes.insert(Class))
|
||||
return;
|
||||
|
||||
// -- If T is a template-id, its associated namespaces and classes are
|
||||
|
@ -2496,7 +2496,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
|
|||
if (!BaseType)
|
||||
continue;
|
||||
CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getDecl());
|
||||
if (Result.Classes.insert(BaseDecl).second) {
|
||||
if (Result.Classes.insert(BaseDecl)) {
|
||||
// Find the associated namespace for this base class.
|
||||
DeclContext *BaseCtx = BaseDecl->getDeclContext();
|
||||
CollectEnclosingNamespace(Result.Namespaces, BaseCtx);
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
// RUN: not %clang_cc1 %s -fsyntax-only 2>&1 | FileCheck %s
|
||||
|
||||
// Ensure that the diagnostics we produce for this situation appear in a
|
||||
// deterministic order. This requires ADL to provide lookup results in a
|
||||
// deterministic order.
|
||||
template<typename T> struct Error { typedef typename T::error error; };
|
||||
struct X { template<typename T> friend typename Error<T>::error f(X, T); };
|
||||
struct Y { template<typename T> friend typename Error<T>::error f(T, Y); };
|
||||
|
||||
void g() {
|
||||
f(X(), Y());
|
||||
}
|
||||
|
||||
// We don't really care which order these two diagnostics appear (although the
|
||||
// order below is source order, which seems best). The crucial fact is that
|
||||
// there is one single order that is stable across multiple runs of clang.
|
||||
//
|
||||
// CHECK: no type named 'error' in 'Y'
|
||||
// CHECK: no type named 'error' in 'X'
|
||||
// CHECK: no matching function for call to 'f'
|
Loading…
Reference in New Issue