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

Commit 48493c8

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

File tree

2 files changed

+125
-2
lines changed

2 files changed

+125
-2
lines changed

lib/AST/ASTStructuralEquivalence.cpp

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,105 @@ 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+
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

111205
static 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.
343454
static 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

test/Analysis/ctu-main.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ void test_implicit(){
5050

5151
// Tests the import of functions that have a struct parameter
5252
// defined in its prototype.
53-
struct data_t{int a;int b;};
54-
int struct_in_proto(struct data_t *d);
53+
int struct_in_proto(struct data_t{int a;int b;} *d);
5554
void test_struct_def_in_argument(){
5655
struct data_t d;
5756
d.a=1;

0 commit comments

Comments
 (0)