@@ -102,11 +102,103 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
102
102
static bool IsStructurallyEquivalent (StructuralEquivalenceContext &Context,
103
103
const TemplateArgument &Arg1,
104
104
const TemplateArgument &Arg2);
105
+ static bool IsStructurallyEquivalent (StructuralEquivalenceContext &Context,
106
+ const TemplateArgumentList &ArgL1,
107
+ const TemplateArgumentList &ArgL2);
105
108
static bool IsStructurallyEquivalent (StructuralEquivalenceContext &Context,
106
109
NestedNameSpecifier *NNS1,
107
110
NestedNameSpecifier *NNS2);
108
111
static bool IsStructurallyEquivalent (const IdentifierInfo *Name1,
109
112
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
+ }
110
202
111
203
static bool IsStructurallyEquivalent (const DeclarationName Name1,
112
204
const DeclarationName Name2) {
@@ -338,6 +430,23 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
338
430
llvm_unreachable (" Invalid template argument kind" );
339
431
}
340
432
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
+
341
450
// / Determine structural equivalence for the common part of array
342
451
// / types.
343
452
static bool IsArrayStructurallyEquivalent (StructuralEquivalenceContext &Context,
@@ -1633,6 +1742,8 @@ unsigned StructuralEquivalenceContext::getApplicableDiagnostic(
1633
1742
return diag::warn_odr_parameter_pack_non_pack;
1634
1743
case diag::err_odr_non_type_parameter_type_inconsistent:
1635
1744
return diag::warn_odr_non_type_parameter_type_inconsistent;
1745
+ default :
1746
+ llvm_unreachable (" Unknown diagnostic type." );
1636
1747
}
1637
1748
}
1638
1749
@@ -1674,6 +1785,17 @@ bool StructuralEquivalenceContext::CheckCommonEquivalence(Decl *D1, Decl *D2) {
1674
1785
1675
1786
// FIXME: Move check for identifier names into this function.
1676
1787
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
+
1677
1799
return true ;
1678
1800
}
1679
1801
0 commit comments