From 48493c87f02add89330c92e1263dc2f7b418e1a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <1.int32@gmail.com> Date: Fri, 8 Mar 2019 12:30:10 +0100 Subject: [PATCH] Scope check at structural equivalence. --- lib/AST/ASTStructuralEquivalence.cpp | 124 +++++++++++++++++++++++++++ test/Analysis/ctu-main.c | 3 +- 2 files changed, 125 insertions(+), 2 deletions(-) diff --git a/lib/AST/ASTStructuralEquivalence.cpp b/lib/AST/ASTStructuralEquivalence.cpp index 378b58c2c63c..dffbd78b5c93 100644 --- a/lib/AST/ASTStructuralEquivalence.cpp +++ b/lib/AST/ASTStructuralEquivalence.cpp @@ -102,11 +102,105 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const TemplateArgument &Arg1, const TemplateArgument &Arg2); +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const TemplateArgumentList &ArgL1, + const TemplateArgumentList &ArgL2); static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, NestedNameSpecifier *NNS1, NestedNameSpecifier *NNS2); static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, const IdentifierInfo *Name2); +static bool IsStructurallyEquivalent(const DeclarationName Name1, + const DeclarationName Name2); + +using ContextVector = llvm::SmallVector; + +static void GetContexts(ContextVector &Contexts, const NamedDecl *ND) { + const DeclContext *Ctx = ND->getDeclContext(); + + // For ObjC methods, look through categories and use the interface as context. + if (auto *MD = dyn_cast(ND)) + if (auto *ID = MD->getClassInterface()) + Ctx = ID; + + if (Ctx->isFunctionOrMethod()) { + Contexts.push_back(Ctx); + return; + } + + // Collect named contexts. + while (Ctx) { + if (isa(Ctx)) + Contexts.push_back(Ctx); + Ctx = Ctx->getParent(); + } +} + +static bool IsEquivalentContext(StructuralEquivalenceContext &Context, const ContextVector &Contexts1, const ContextVector &Contexts2) { + auto DC2I = Contexts2.begin(); + for (const DeclContext *DC1 : Contexts1) { + if (DC2I == Contexts2.end()) + return false; + const DeclContext *DC2 = *DC2I; + ++DC2I; + + if (const auto *Spec1 = dyn_cast(DC1)) { + const auto *Spec2 = dyn_cast(DC2); + if (!Spec2) + return false; + if (!IsStructurallyEquivalent(Spec1->getDeclName(), Spec2->getDeclName())) + return false; + if (!IsStructurallyEquivalent(Context, Spec1->getTemplateArgs(), Spec2->getTemplateArgs())) + return false; + } else if (const auto *ND1 = dyn_cast(DC1)) { + const auto *ND2 = dyn_cast(DC2); + if (!ND2) + return false; + if (ND1->isAnonymousNamespace() != ND2->isAnonymousNamespace()) + return false; + if (ND1->isInline() != ND2->isInline()) + return false; + if (ND1->isAnonymousNamespace() || ND1->isInlineNamespace()) + continue; + if (!IsStructurallyEquivalent(ND1->getDeclName(), ND2->getDeclName())) + return false; + } else if (const auto *RD1 = dyn_cast(DC1)) { + const auto *RD2 = dyn_cast(DC2); + if (!RD2) + return false; + if (!IsStructurallyEquivalent(RD1->getDeclName(), RD2->getDeclName())) + return false; + } else if (const auto *FD1 = dyn_cast(DC1)) { + const auto *FD2 = dyn_cast(DC2); + if (!FD2) + return false; + if (!IsStructurallyEquivalent(Context, const_cast(FD1), const_cast(FD2))) + return false; + /*} else if (const auto *ED = dyn_cast(DC)) { + // C++ [dcl.enum]p10: Each enum-name and each unscoped + // enumerator is declared in the scope that immediately contains + // the enum-specifier. Each scoped enumerator is declared in the + // scope of the enumeration. + // For the case of unscoped enumerator, do not include in the qualified + // name any information about its enum enclosing scope, as its visibility + // is global. + if (ED->isScoped()) + OS << *ED; + else + continue;*/ + } else if (const auto *ND1 = dyn_cast(DC1)) { + const auto *ND2 = cast(DC2); + if (!IsStructurallyEquivalent(ND1->getDeclName(), ND2->getDeclName())) + return false; + } else + llvm_unreachable("Context should be NamedDecl."); + } + + if (DC2I != Contexts2.end()) + return false; + + return true; +} static bool IsStructurallyEquivalent(const DeclarationName Name1, const DeclarationName Name2) { @@ -338,6 +432,23 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, llvm_unreachable("Invalid template argument kind"); } +/// Determine whether two template argument lists are equivalent. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const TemplateArgumentList &ArgL1, + const TemplateArgumentList &ArgL2) { + if (ArgL1.size() != ArgL2.size()) { + if (Context.Complain) { + } + return false; + } + + for (unsigned I = 0, N = ArgL1.size(); I != N; ++I) + if (!IsStructurallyEquivalent(Context, ArgL1.get(I), ArgL2.get(I))) + return false; + + return true; +} + /// Determine structural equivalence for the common part of array /// types. static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context, @@ -1633,6 +1744,8 @@ unsigned StructuralEquivalenceContext::getApplicableDiagnostic( return diag::warn_odr_parameter_pack_non_pack; case diag::err_odr_non_type_parameter_type_inconsistent: return diag::warn_odr_non_type_parameter_type_inconsistent; + default: + llvm_unreachable("Unknown diagnostic type."); } } @@ -1674,6 +1787,17 @@ bool StructuralEquivalenceContext::CheckCommonEquivalence(Decl *D1, Decl *D2) { // FIXME: Move check for identifier names into this function. + if (auto *ND1 = dyn_cast(D1)) { + auto *ND2 = dyn_cast(D2); + if (!ND2) + return false; + ContextVector Contexts1, Contexts2; + GetContexts(Contexts1, ND1); + GetContexts(Contexts2, ND2); + if (!IsEquivalentContext(*this, Contexts1, Contexts2)) + return false; + } + return true; } diff --git a/test/Analysis/ctu-main.c b/test/Analysis/ctu-main.c index 7c266f1e8de2..184a6a45b56b 100644 --- a/test/Analysis/ctu-main.c +++ b/test/Analysis/ctu-main.c @@ -50,8 +50,7 @@ void test_implicit(){ // Tests the import of functions that have a struct parameter // defined in its prototype. -struct data_t{int a;int b;}; -int struct_in_proto(struct data_t *d); +int struct_in_proto(struct data_t{int a;int b;} *d); void test_struct_def_in_argument(){ struct data_t d; d.a=1;