@@ -102,11 +102,105 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
102102static 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);
105108static bool IsStructurallyEquivalent (StructuralEquivalenceContext &Context,
106109 NestedNameSpecifier *NNS1,
107110 NestedNameSpecifier *NNS2);
108111static 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+ if (Ctx->isFunctionOrMethod ()) {
127+ Contexts.push_back (Ctx);
128+ return ;
129+ }
130+
131+ // Collect named contexts.
132+ while (Ctx) {
133+ if (isa<NamedDecl>(Ctx))
134+ Contexts.push_back (Ctx);
135+ Ctx = Ctx->getParent ();
136+ }
137+ }
138+
139+ static bool IsEquivalentContext (StructuralEquivalenceContext &Context, const ContextVector &Contexts1, const ContextVector &Contexts2) {
140+ auto DC2I = Contexts2.begin ();
141+ for (const DeclContext *DC1 : Contexts1) {
142+ if (DC2I == Contexts2.end ())
143+ return false ;
144+ const DeclContext *DC2 = *DC2I;
145+ ++DC2I;
146+
147+ if (const auto *Spec1 = dyn_cast<ClassTemplateSpecializationDecl>(DC1)) {
148+ const auto *Spec2 = dyn_cast<ClassTemplateSpecializationDecl>(DC2);
149+ if (!Spec2)
150+ return false ;
151+ if (!IsStructurallyEquivalent (Spec1->getDeclName (), Spec2->getDeclName ()))
152+ return false ;
153+ if (!IsStructurallyEquivalent (Context, Spec1->getTemplateArgs (), Spec2->getTemplateArgs ()))
154+ return false ;
155+ } else if (const auto *ND1 = dyn_cast<NamespaceDecl>(DC1)) {
156+ const auto *ND2 = dyn_cast<NamespaceDecl>(DC2);
157+ if (!ND2)
158+ return false ;
159+ if (ND1->isAnonymousNamespace () != ND2->isAnonymousNamespace ())
160+ return false ;
161+ if (ND1->isInline () != ND2->isInline ())
162+ return false ;
163+ if (ND1->isAnonymousNamespace () || ND1->isInlineNamespace ())
164+ continue ;
165+ if (!IsStructurallyEquivalent (ND1->getDeclName (), ND2->getDeclName ()))
166+ return false ;
167+ } else if (const auto *RD1 = dyn_cast<RecordDecl>(DC1)) {
168+ const auto *RD2 = dyn_cast<RecordDecl>(DC2);
169+ if (!RD2)
170+ return false ;
171+ if (!IsStructurallyEquivalent (RD1->getDeclName (), RD2->getDeclName ()))
172+ return false ;
173+ } else if (const auto *FD1 = dyn_cast<FunctionDecl>(DC1)) {
174+ const auto *FD2 = dyn_cast<FunctionDecl>(DC2);
175+ if (!FD2)
176+ return false ;
177+ if (!IsStructurallyEquivalent (Context, const_cast <FunctionDecl *>(FD1), const_cast <FunctionDecl *>(FD2)))
178+ return false ;
179+ /* } else if (const auto *ED = dyn_cast<EnumDecl>(DC)) {
180+ // C++ [dcl.enum]p10: Each enum-name and each unscoped
181+ // enumerator is declared in the scope that immediately contains
182+ // the enum-specifier. Each scoped enumerator is declared in the
183+ // scope of the enumeration.
184+ // For the case of unscoped enumerator, do not include in the qualified
185+ // name any information about its enum enclosing scope, as its visibility
186+ // is global.
187+ if (ED->isScoped())
188+ OS << *ED;
189+ else
190+ continue;*/
191+ } else if (const auto *ND1 = dyn_cast<NamedDecl>(DC1)) {
192+ const auto *ND2 = cast<NamedDecl>(DC2);
193+ if (!IsStructurallyEquivalent (ND1->getDeclName (), ND2->getDeclName ()))
194+ return false ;
195+ } else
196+ llvm_unreachable (" Context should be NamedDecl." );
197+ }
198+
199+ if (DC2I != Contexts2.end ())
200+ return false ;
201+
202+ return true ;
203+ }
110204
111205static bool IsStructurallyEquivalent (const DeclarationName Name1,
112206 const DeclarationName Name2) {
@@ -338,6 +432,23 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
338432 llvm_unreachable (" Invalid template argument kind" );
339433}
340434
435+ // / Determine whether two template argument lists are equivalent.
436+ static bool IsStructurallyEquivalent (StructuralEquivalenceContext &Context,
437+ const TemplateArgumentList &ArgL1,
438+ const TemplateArgumentList &ArgL2) {
439+ if (ArgL1.size () != ArgL2.size ()) {
440+ if (Context.Complain ) {
441+ }
442+ return false ;
443+ }
444+
445+ for (unsigned I = 0 , N = ArgL1.size (); I != N; ++I)
446+ if (!IsStructurallyEquivalent (Context, ArgL1.get (I), ArgL2.get (I)))
447+ return false ;
448+
449+ return true ;
450+ }
451+
341452// / Determine structural equivalence for the common part of array
342453// / types.
343454static bool IsArrayStructurallyEquivalent (StructuralEquivalenceContext &Context,
@@ -1633,6 +1744,8 @@ unsigned StructuralEquivalenceContext::getApplicableDiagnostic(
16331744 return diag::warn_odr_parameter_pack_non_pack;
16341745 case diag::err_odr_non_type_parameter_type_inconsistent:
16351746 return diag::warn_odr_non_type_parameter_type_inconsistent;
1747+ default :
1748+ llvm_unreachable (" Unknown diagnostic type." );
16361749 }
16371750}
16381751
@@ -1674,6 +1787,17 @@ bool StructuralEquivalenceContext::CheckCommonEquivalence(Decl *D1, Decl *D2) {
16741787
16751788 // FIXME: Move check for identifier names into this function.
16761789
1790+ if (auto *ND1 = dyn_cast<NamedDecl>(D1)) {
1791+ auto *ND2 = dyn_cast<NamedDecl>(D2);
1792+ if (!ND2)
1793+ return false ;
1794+ ContextVector Contexts1, Contexts2;
1795+ GetContexts (Contexts1, ND1);
1796+ GetContexts (Contexts2, ND2);
1797+ if (!IsEquivalentContext (*this , Contexts1, Contexts2))
1798+ return false ;
1799+ }
1800+
16771801 return true ;
16781802}
16791803
0 commit comments