From c81af03fb39c879f1713224b29ac0fc10470ea89 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Thu, 29 Jul 2010 18:15:58 +0000 Subject: Merge PCHWriterDecl.cpp's isRequiredDecl and CodeGenModule::MayDeferGeneration into a new function, DeclIsRequiredFunctionOrFileScopedVar. This is essentially a CodeGen predicate that is also needed by the PCH mechanism to determine whether a decl needs to be deserialized during PCH loading for codegen purposes. Since this logic is shared by CodeGen and the PCH mechanism, move it to the ASTContext, thus CodeGenModule's GetLinkageForFunction/GetLinkageForVariable and the GVALinkage enum is moved out of CodeGen. This fixes current (and avoids future) codegen-from-PCH bugs. llvm-svn: 109784 --- clang/lib/AST/ASTContext.cpp | 160 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) (limited to 'clang/lib/AST/ASTContext.cpp') diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 4fd8f661086..af19e89fd9d 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -5445,3 +5445,163 @@ ASTContext::UsualArithmeticConversionsType(QualType lhs, QualType rhs) { } return destType; } + +GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) { + GVALinkage External = GVA_StrongExternal; + + Linkage L = FD->getLinkage(); + if (L == ExternalLinkage && getLangOptions().CPlusPlus && + FD->getType()->getLinkage() == UniqueExternalLinkage) + L = UniqueExternalLinkage; + + switch (L) { + case NoLinkage: + case InternalLinkage: + case UniqueExternalLinkage: + return GVA_Internal; + + case ExternalLinkage: + switch (FD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + External = GVA_StrongExternal; + break; + + case TSK_ExplicitInstantiationDefinition: + return GVA_ExplicitTemplateInstantiation; + + case TSK_ExplicitInstantiationDeclaration: + case TSK_ImplicitInstantiation: + External = GVA_TemplateInstantiation; + break; + } + } + + if (!FD->isInlined()) + return External; + + if (!getLangOptions().CPlusPlus || FD->hasAttr()) { + // GNU or C99 inline semantics. Determine whether this symbol should be + // externally visible. + if (FD->isInlineDefinitionExternallyVisible()) + return External; + + // C99 inline semantics, where the symbol is not externally visible. + return GVA_C99Inline; + } + + // C++0x [temp.explicit]p9: + // [ Note: The intent is that an inline function that is the subject of + // an explicit instantiation declaration will still be implicitly + // instantiated when used so that the body can be considered for + // inlining, but that no out-of-line copy of the inline function would be + // generated in the translation unit. -- end note ] + if (FD->getTemplateSpecializationKind() + == TSK_ExplicitInstantiationDeclaration) + return GVA_C99Inline; + + return GVA_CXXInline; +} + +GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) { + // If this is a static data member, compute the kind of template + // specialization. Otherwise, this variable is not part of a + // template. + TemplateSpecializationKind TSK = TSK_Undeclared; + if (VD->isStaticDataMember()) + TSK = VD->getTemplateSpecializationKind(); + + Linkage L = VD->getLinkage(); + if (L == ExternalLinkage && getLangOptions().CPlusPlus && + VD->getType()->getLinkage() == UniqueExternalLinkage) + L = UniqueExternalLinkage; + + switch (L) { + case NoLinkage: + case InternalLinkage: + case UniqueExternalLinkage: + return GVA_Internal; + + case ExternalLinkage: + switch (TSK) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + return GVA_StrongExternal; + + case TSK_ExplicitInstantiationDeclaration: + llvm_unreachable("Variable should not be instantiated"); + // Fall through to treat this like any other instantiation. + + case TSK_ExplicitInstantiationDefinition: + return GVA_ExplicitTemplateInstantiation; + + case TSK_ImplicitInstantiation: + return GVA_TemplateInstantiation; + } + } + + return GVA_StrongExternal; +} + +bool ASTContext::DeclIsRequiredFunctionOrFileScopedVar(const Decl *D) { + if (const VarDecl *VD = dyn_cast(D)) { + if (!VD->isFileVarDecl()) + return false; + } else if (!isa(D)) + return false; + + // Aliases and used decls are required. + if (D->hasAttr() || D->hasAttr()) + return true; + + if (const FunctionDecl *FD = dyn_cast(D)) { + // Forward declarations aren't required. + if (!FD->isThisDeclarationADefinition()) + return false; + + // Constructors and destructors are required. + if (FD->hasAttr() || FD->hasAttr()) + return true; + + // The key function for a class is required. + if (const CXXMethodDecl *MD = dyn_cast(FD)) { + const CXXRecordDecl *RD = MD->getParent(); + if (MD->isOutOfLine() && RD->isDynamicClass()) { + const CXXMethodDecl *KeyFunc = getKeyFunction(RD); + if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl()) + return true; + } + } + + GVALinkage Linkage = GetGVALinkageForFunction(FD); + + // static, static inline, always_inline, and extern inline functions can + // always be deferred. Normal inline functions can be deferred in C99/C++. + // Implicit template instantiations can also be deferred in C++. + if (Linkage == GVA_Internal || Linkage == GVA_C99Inline || + Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation) + return false; + return true; + } + + const VarDecl *VD = cast(D); + assert(VD->isFileVarDecl() && "Expected file scoped var"); + + // Structs that have non-trivial constructors or destructors are required. + + // FIXME: Handle references. + if (const RecordType *RT = VD->getType()->getAs()) { + if (const CXXRecordDecl *RD = dyn_cast(RT->getDecl())) { + if (!RD->hasTrivialConstructor() || !RD->hasTrivialDestructor()) + return true; + } + } + + GVALinkage L = GetGVALinkageForVariable(VD); + if (L == GVA_Internal || L == GVA_TemplateInstantiation) { + if (!(VD->getInit() && VD->getInit()->HasSideEffects(*this))) + return false; + } + + return true; +} -- cgit v1.2.3