|
@@ -1574,20 +1574,24 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
|
Decl *D1, Decl *D2) {
|
|
Decl *D1, Decl *D2) {
|
|
// FIXME: Check for known structural equivalences via a callback of some sort.
|
|
// FIXME: Check for known structural equivalences via a callback of some sort.
|
|
|
|
|
|
|
|
+ D1 = D1->getCanonicalDecl();
|
|
|
|
+ D2 = D2->getCanonicalDecl();
|
|
|
|
+ std::pair<Decl *, Decl *> P{D1, D2};
|
|
|
|
+
|
|
// Check whether we already know that these two declarations are not
|
|
// Check whether we already know that these two declarations are not
|
|
// structurally equivalent.
|
|
// structurally equivalent.
|
|
- if (Context.NonEquivalentDecls.count(
|
|
|
|
- std::make_pair(D1->getCanonicalDecl(), D2->getCanonicalDecl())))
|
|
|
|
|
|
+ if (Context.NonEquivalentDecls.count(P))
|
|
return false;
|
|
return false;
|
|
|
|
|
|
- // Determine whether we've already produced a tentative equivalence for D1.
|
|
|
|
- Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()];
|
|
|
|
- if (EquivToD1)
|
|
|
|
- return EquivToD1 == D2->getCanonicalDecl();
|
|
|
|
|
|
+ // Check if a check for these declarations is already pending.
|
|
|
|
+ // If yes D1 and D2 will be checked later (from DeclsToCheck),
|
|
|
|
+ // or these are already checked (and equivalent).
|
|
|
|
+ bool Inserted = Context.VisitedDecls.insert(P).second;
|
|
|
|
+ if (!Inserted)
|
|
|
|
+ return true;
|
|
|
|
+
|
|
|
|
+ Context.DeclsToCheck.push(P);
|
|
|
|
|
|
- // Produce a tentative equivalence D1 <-> D2, which will be checked later.
|
|
|
|
- EquivToD1 = D2->getCanonicalDecl();
|
|
|
|
- Context.DeclsToCheck.push_back(D1->getCanonicalDecl());
|
|
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1703,11 +1707,13 @@ bool StructuralEquivalenceContext::IsEquivalent(Decl *D1, Decl *D2) {
|
|
// Ensure that the implementation functions (all static functions in this TU)
|
|
// Ensure that the implementation functions (all static functions in this TU)
|
|
// never call the public ASTStructuralEquivalence::IsEquivalent() functions,
|
|
// never call the public ASTStructuralEquivalence::IsEquivalent() functions,
|
|
// because that will wreak havoc the internal state (DeclsToCheck and
|
|
// because that will wreak havoc the internal state (DeclsToCheck and
|
|
- // TentativeEquivalences members) and can cause faulty behaviour. For
|
|
|
|
- // instance, some leaf declarations can be stated and cached as inequivalent
|
|
|
|
- // as a side effect of one inequivalent element in the DeclsToCheck list.
|
|
|
|
|
|
+ // VisitedDecls members) and can cause faulty behaviour.
|
|
|
|
+ // In other words: Do not start a graph search from a new node with the
|
|
|
|
+ // internal data of another search in progress.
|
|
|
|
+ // FIXME: Better encapsulation and separation of internal and public
|
|
|
|
+ // functionality.
|
|
assert(DeclsToCheck.empty());
|
|
assert(DeclsToCheck.empty());
|
|
- assert(TentativeEquivalences.empty());
|
|
|
|
|
|
+ assert(VisitedDecls.empty());
|
|
|
|
|
|
if (!::IsStructurallyEquivalent(*this, D1, D2))
|
|
if (!::IsStructurallyEquivalent(*this, D1, D2))
|
|
return false;
|
|
return false;
|
|
@@ -1717,7 +1723,7 @@ bool StructuralEquivalenceContext::IsEquivalent(Decl *D1, Decl *D2) {
|
|
|
|
|
|
bool StructuralEquivalenceContext::IsEquivalent(QualType T1, QualType T2) {
|
|
bool StructuralEquivalenceContext::IsEquivalent(QualType T1, QualType T2) {
|
|
assert(DeclsToCheck.empty());
|
|
assert(DeclsToCheck.empty());
|
|
- assert(TentativeEquivalences.empty());
|
|
|
|
|
|
+ assert(VisitedDecls.empty());
|
|
if (!::IsStructurallyEquivalent(*this, T1, T2))
|
|
if (!::IsStructurallyEquivalent(*this, T1, T2))
|
|
return false;
|
|
return false;
|
|
|
|
|
|
@@ -1876,11 +1882,11 @@ bool StructuralEquivalenceContext::CheckKindSpecificEquivalence(
|
|
bool StructuralEquivalenceContext::Finish() {
|
|
bool StructuralEquivalenceContext::Finish() {
|
|
while (!DeclsToCheck.empty()) {
|
|
while (!DeclsToCheck.empty()) {
|
|
// Check the next declaration.
|
|
// Check the next declaration.
|
|
- Decl *D1 = DeclsToCheck.front();
|
|
|
|
- DeclsToCheck.pop_front();
|
|
|
|
|
|
+ std::pair<Decl *, Decl *> P = DeclsToCheck.front();
|
|
|
|
+ DeclsToCheck.pop();
|
|
|
|
|
|
- Decl *D2 = TentativeEquivalences[D1];
|
|
|
|
- assert(D2 && "Unrecorded tentative equivalence?");
|
|
|
|
|
|
+ Decl *D1 = P.first;
|
|
|
|
+ Decl *D2 = P.second;
|
|
|
|
|
|
bool Equivalent =
|
|
bool Equivalent =
|
|
CheckCommonEquivalence(D1, D2) && CheckKindSpecificEquivalence(D1, D2);
|
|
CheckCommonEquivalence(D1, D2) && CheckKindSpecificEquivalence(D1, D2);
|
|
@@ -1888,8 +1894,8 @@ bool StructuralEquivalenceContext::Finish() {
|
|
if (!Equivalent) {
|
|
if (!Equivalent) {
|
|
// Note that these two declarations are not equivalent (and we already
|
|
// Note that these two declarations are not equivalent (and we already
|
|
// know about it).
|
|
// know about it).
|
|
- NonEquivalentDecls.insert(
|
|
|
|
- std::make_pair(D1->getCanonicalDecl(), D2->getCanonicalDecl()));
|
|
|
|
|
|
+ NonEquivalentDecls.insert(P);
|
|
|
|
+
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|