Skip to content
This repository was archived by the owner on Mar 30, 2021. It is now read-only.

Commit abc67c7

Browse files
committed
Scope check at structural equivalence.
1 parent 8cebd4d commit abc67c7

File tree

1 file changed

+122
-0
lines changed

1 file changed

+122
-0
lines changed

lib/AST/ASTStructuralEquivalence.cpp

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,103 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
102102
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
103103
const TemplateArgument &Arg1,
104104
const TemplateArgument &Arg2);
105+
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
106+
const TemplateArgumentList &ArgL1,
107+
const TemplateArgumentList &ArgL2);
105108
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
106109
NestedNameSpecifier *NNS1,
107110
NestedNameSpecifier *NNS2);
108111
static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
109112
const IdentifierInfo *Name2);
113+
static bool IsStructurallyEquivalent(const DeclarationName Name1,
114+
const DeclarationName Name2);
115+
116+
using ContextVector = llvm::SmallVector<const DeclContext *, 4>;
117+
118+
static void GetContexts(ContextVector &Contexts, const NamedDecl *ND) {
119+
const DeclContext *Ctx = ND->getDeclContext();
120+
121+
// For ObjC methods, look through categories and use the interface as context.
122+
if (auto *MD = dyn_cast<ObjCMethodDecl>(ND))
123+
if (auto *ID = MD->getClassInterface())
124+
Ctx = ID;
125+
126+
while (Ctx && Ctx->isFunctionOrMethod())
127+
Ctx = Ctx->getParent();
128+
129+
// Collect named contexts.
130+
while (Ctx) {
131+
if (isa<NamedDecl>(Ctx))
132+
Contexts.push_back(Ctx);
133+
Ctx = Ctx->getParent();
134+
}
135+
}
136+
137+
static bool IsEquivalentContext(StructuralEquivalenceContext &Context, const ContextVector &Contexts1, const ContextVector &Contexts2) {
138+
auto DC2I = Contexts2.begin();
139+
for (const DeclContext *DC1 : Contexts1) {
140+
if (DC2I == Contexts2.end())
141+
return false;
142+
const DeclContext *DC2 = *DC2I;
143+
++DC2I;
144+
145+
if (const auto *Spec1 = dyn_cast<ClassTemplateSpecializationDecl>(DC1)) {
146+
const auto *Spec2 = dyn_cast<ClassTemplateSpecializationDecl>(DC2);
147+
if (!Spec2)
148+
return false;
149+
if (!IsStructurallyEquivalent(Spec1->getDeclName(), Spec2->getDeclName()))
150+
return false;
151+
if (!IsStructurallyEquivalent(Context, Spec1->getTemplateArgs(), Spec2->getTemplateArgs()))
152+
return false;
153+
} else if (const auto *ND1 = dyn_cast<NamespaceDecl>(DC1)) {
154+
const auto *ND2 = dyn_cast<NamespaceDecl>(DC2);
155+
if (!ND2)
156+
return false;
157+
if (ND1->isAnonymousNamespace() != ND2->isAnonymousNamespace())
158+
return false;
159+
if (ND1->isInline() != ND2->isInline())
160+
return false;
161+
if (ND1->isAnonymousNamespace() || ND1->isInlineNamespace())
162+
continue;
163+
if (!IsStructurallyEquivalent(ND1->getDeclName(), ND2->getDeclName()))
164+
return false;
165+
} else if (const auto *RD1 = dyn_cast<RecordDecl>(DC1)) {
166+
const auto *RD2 = dyn_cast<RecordDecl>(DC2);
167+
if (!RD2)
168+
return false;
169+
if (!IsStructurallyEquivalent(RD1->getDeclName(), RD2->getDeclName()))
170+
return false;
171+
} else if (const auto *FD1 = dyn_cast<FunctionDecl>(DC1)) {
172+
const auto *FD2 = dyn_cast<FunctionDecl>(DC2);
173+
if (!FD2)
174+
return false;
175+
if (!IsStructurallyEquivalent(Context, const_cast<FunctionDecl *>(FD1), const_cast<FunctionDecl *>(FD2)))
176+
return false;
177+
/*} else if (const auto *ED = dyn_cast<EnumDecl>(DC)) {
178+
// C++ [dcl.enum]p10: Each enum-name and each unscoped
179+
// enumerator is declared in the scope that immediately contains
180+
// the enum-specifier. Each scoped enumerator is declared in the
181+
// scope of the enumeration.
182+
// For the case of unscoped enumerator, do not include in the qualified
183+
// name any information about its enum enclosing scope, as its visibility
184+
// is global.
185+
if (ED->isScoped())
186+
OS << *ED;
187+
else
188+
continue;*/
189+
} else if (const auto *ND1 = dyn_cast<NamedDecl>(DC1)) {
190+
const auto *ND2 = cast<NamedDecl>(DC2);
191+
if (!IsStructurallyEquivalent(ND1->getDeclName(), ND2->getDeclName()))
192+
return false;
193+
} else
194+
llvm_unreachable("Context should be NamedDecl.");
195+
}
196+
197+
if (DC2I != Contexts2.end())
198+
return false;
199+
200+
return true;
201+
}
110202

111203
static bool IsStructurallyEquivalent(const DeclarationName Name1,
112204
const DeclarationName Name2) {
@@ -338,6 +430,23 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
338430
llvm_unreachable("Invalid template argument kind");
339431
}
340432

433+
/// Determine whether two template argument lists are equivalent.
434+
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
435+
const TemplateArgumentList &ArgL1,
436+
const TemplateArgumentList &ArgL2) {
437+
if (ArgL1.size() != ArgL2.size()) {
438+
if (Context.Complain) {
439+
}
440+
return false;
441+
}
442+
443+
for (unsigned I = 0, N = ArgL1.size(); I != N; ++I)
444+
if (!IsStructurallyEquivalent(Context, ArgL1.get(I), ArgL2.get(I)))
445+
return false;
446+
447+
return true;
448+
}
449+
341450
/// Determine structural equivalence for the common part of array
342451
/// types.
343452
static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context,
@@ -1633,6 +1742,8 @@ unsigned StructuralEquivalenceContext::getApplicableDiagnostic(
16331742
return diag::warn_odr_parameter_pack_non_pack;
16341743
case diag::err_odr_non_type_parameter_type_inconsistent:
16351744
return diag::warn_odr_non_type_parameter_type_inconsistent;
1745+
default:
1746+
llvm_unreachable("Unknown diagnostic type.");
16361747
}
16371748
}
16381749

@@ -1674,6 +1785,17 @@ bool StructuralEquivalenceContext::CheckCommonEquivalence(Decl *D1, Decl *D2) {
16741785

16751786
// FIXME: Move check for identifier names into this function.
16761787

1788+
if (auto *ND1 = dyn_cast<NamedDecl>(D1)) {
1789+
auto *ND2 = dyn_cast<NamedDecl>(D2);
1790+
if (!ND2)
1791+
return false;
1792+
ContextVector Contexts1, Contexts2;
1793+
GetContexts(Contexts1, ND1);
1794+
GetContexts(Contexts2, ND2);
1795+
if (!IsEquivalentContext(*this, Contexts1, Contexts2))
1796+
return false;
1797+
}
1798+
16771799
return true;
16781800
}
16791801

0 commit comments

Comments
 (0)