@@ -102,11 +102,103 @@ 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+ 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
111203static 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.
343452static 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