10b57cec5SDimitry Andric //===----- Linkage.h - Linkage calculation-related utilities ----*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file provides AST-internal utilities for linkage and visibility 100b57cec5SDimitry Andric // calculation. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #ifndef LLVM_CLANG_LIB_AST_LINKAGE_H 150b57cec5SDimitry Andric #define LLVM_CLANG_LIB_AST_LINKAGE_H 160b57cec5SDimitry Andric 175ffd83dbSDimitry Andric #include "clang/AST/ASTFwd.h" 180b57cec5SDimitry Andric #include "clang/AST/Decl.h" 190b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h" 200b57cec5SDimitry Andric #include "clang/AST/Type.h" 210b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 220b57cec5SDimitry Andric #include "llvm/ADT/PointerIntPair.h" 23bdd1243dSDimitry Andric #include <optional> 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric namespace clang { 260b57cec5SDimitry Andric /// Kinds of LV computation. The linkage side of the computation is 270b57cec5SDimitry Andric /// always the same, but different things can change how visibility is 280b57cec5SDimitry Andric /// computed. 290b57cec5SDimitry Andric struct LVComputationKind { 300b57cec5SDimitry Andric /// The kind of entity whose visibility is ultimately being computed; 310b57cec5SDimitry Andric /// visibility computations for types and non-types follow different rules. 32*0fca6ea1SDimitry Andric LLVM_PREFERRED_TYPE(bool) 330b57cec5SDimitry Andric unsigned ExplicitKind : 1; 340b57cec5SDimitry Andric /// Whether explicit visibility attributes should be ignored. When set, 350b57cec5SDimitry Andric /// visibility may only be restricted by the visibility of template arguments. 36*0fca6ea1SDimitry Andric LLVM_PREFERRED_TYPE(bool) 370b57cec5SDimitry Andric unsigned IgnoreExplicitVisibility : 1; 380b57cec5SDimitry Andric /// Whether all visibility should be ignored. When set, we're only interested 390b57cec5SDimitry Andric /// in computing linkage. 40*0fca6ea1SDimitry Andric LLVM_PREFERRED_TYPE(bool) 410b57cec5SDimitry Andric unsigned IgnoreAllVisibility : 1; 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric enum { NumLVComputationKindBits = 3 }; 440b57cec5SDimitry Andric LVComputationKindLVComputationKind450b57cec5SDimitry Andric explicit LVComputationKind(NamedDecl::ExplicitVisibilityKind EK) 460b57cec5SDimitry Andric : ExplicitKind(EK), IgnoreExplicitVisibility(false), 470b57cec5SDimitry Andric IgnoreAllVisibility(false) {} 480b57cec5SDimitry Andric getExplicitVisibilityKindLVComputationKind490b57cec5SDimitry Andric NamedDecl::ExplicitVisibilityKind getExplicitVisibilityKind() const { 500b57cec5SDimitry Andric return static_cast<NamedDecl::ExplicitVisibilityKind>(ExplicitKind); 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric isTypeVisibilityLVComputationKind530b57cec5SDimitry Andric bool isTypeVisibility() const { 540b57cec5SDimitry Andric return getExplicitVisibilityKind() == NamedDecl::VisibilityForType; 550b57cec5SDimitry Andric } isValueVisibilityLVComputationKind560b57cec5SDimitry Andric bool isValueVisibility() const { 570b57cec5SDimitry Andric return getExplicitVisibilityKind() == NamedDecl::VisibilityForValue; 580b57cec5SDimitry Andric } 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric /// Do an LV computation when we only care about the linkage. forLinkageOnlyLVComputationKind610b57cec5SDimitry Andric static LVComputationKind forLinkageOnly() { 620b57cec5SDimitry Andric LVComputationKind Result(NamedDecl::VisibilityForValue); 630b57cec5SDimitry Andric Result.IgnoreExplicitVisibility = true; 640b57cec5SDimitry Andric Result.IgnoreAllVisibility = true; 650b57cec5SDimitry Andric return Result; 660b57cec5SDimitry Andric } 670b57cec5SDimitry Andric toBitsLVComputationKind680b57cec5SDimitry Andric unsigned toBits() { 690b57cec5SDimitry Andric unsigned Bits = 0; 700b57cec5SDimitry Andric Bits = (Bits << 1) | ExplicitKind; 710b57cec5SDimitry Andric Bits = (Bits << 1) | IgnoreExplicitVisibility; 720b57cec5SDimitry Andric Bits = (Bits << 1) | IgnoreAllVisibility; 730b57cec5SDimitry Andric return Bits; 740b57cec5SDimitry Andric } 750b57cec5SDimitry Andric }; 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric class LinkageComputer { 780b57cec5SDimitry Andric // We have a cache for repeated linkage/visibility computations. This saves us 790b57cec5SDimitry Andric // from exponential behavior in heavily templated code, such as: 800b57cec5SDimitry Andric // 810b57cec5SDimitry Andric // template <typename T, typename V> struct {}; 820b57cec5SDimitry Andric // using A = int; 830b57cec5SDimitry Andric // using B = Foo<A, A>; 840b57cec5SDimitry Andric // using C = Foo<B, B>; 850b57cec5SDimitry Andric // using D = Foo<C, C>; 860b57cec5SDimitry Andric // 870b57cec5SDimitry Andric // The integer represents an LVComputationKind. 880b57cec5SDimitry Andric using QueryType = 890b57cec5SDimitry Andric llvm::PointerIntPair<const NamedDecl *, 900b57cec5SDimitry Andric LVComputationKind::NumLVComputationKindBits>; 910b57cec5SDimitry Andric llvm::SmallDenseMap<QueryType, LinkageInfo, 8> CachedLinkageInfo; 920b57cec5SDimitry Andric makeCacheKey(const NamedDecl * ND,LVComputationKind Kind)930b57cec5SDimitry Andric static QueryType makeCacheKey(const NamedDecl *ND, LVComputationKind Kind) { 940b57cec5SDimitry Andric return QueryType(ND, Kind.toBits()); 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric lookup(const NamedDecl * ND,LVComputationKind Kind)97bdd1243dSDimitry Andric std::optional<LinkageInfo> lookup(const NamedDecl *ND, 980b57cec5SDimitry Andric LVComputationKind Kind) const { 990b57cec5SDimitry Andric auto Iter = CachedLinkageInfo.find(makeCacheKey(ND, Kind)); 1000b57cec5SDimitry Andric if (Iter == CachedLinkageInfo.end()) 101bdd1243dSDimitry Andric return std::nullopt; 1020b57cec5SDimitry Andric return Iter->second; 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric cache(const NamedDecl * ND,LVComputationKind Kind,LinkageInfo Info)1050b57cec5SDimitry Andric void cache(const NamedDecl *ND, LVComputationKind Kind, LinkageInfo Info) { 1060b57cec5SDimitry Andric CachedLinkageInfo[makeCacheKey(ND, Kind)] = Info; 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric LinkageInfo getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args, 1100b57cec5SDimitry Andric LVComputationKind computation); 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric LinkageInfo getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, 1130b57cec5SDimitry Andric LVComputationKind computation); 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric void mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn, 1160b57cec5SDimitry Andric const FunctionTemplateSpecializationInfo *specInfo, 1170b57cec5SDimitry Andric LVComputationKind computation); 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric void mergeTemplateLV(LinkageInfo &LV, 1200b57cec5SDimitry Andric const ClassTemplateSpecializationDecl *spec, 1210b57cec5SDimitry Andric LVComputationKind computation); 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric void mergeTemplateLV(LinkageInfo &LV, 1240b57cec5SDimitry Andric const VarTemplateSpecializationDecl *spec, 1250b57cec5SDimitry Andric LVComputationKind computation); 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, 1280b57cec5SDimitry Andric LVComputationKind computation, 1290b57cec5SDimitry Andric bool IgnoreVarTypeLinkage); 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric LinkageInfo getLVForClassMember(const NamedDecl *D, 1320b57cec5SDimitry Andric LVComputationKind computation, 1330b57cec5SDimitry Andric bool IgnoreVarTypeLinkage); 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl, 1360b57cec5SDimitry Andric LVComputationKind computation); 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric LinkageInfo getLVForLocalDecl(const NamedDecl *D, 1390b57cec5SDimitry Andric LVComputationKind computation); 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric LinkageInfo getLVForType(const Type &T, LVComputationKind computation); 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric LinkageInfo getLVForTemplateParameterList(const TemplateParameterList *Params, 1440b57cec5SDimitry Andric LVComputationKind computation); 1450b57cec5SDimitry Andric 146e8d8bef9SDimitry Andric LinkageInfo getLVForValue(const APValue &V, LVComputationKind computation); 147e8d8bef9SDimitry Andric 1480b57cec5SDimitry Andric public: 1490b57cec5SDimitry Andric LinkageInfo computeLVForDecl(const NamedDecl *D, 1500b57cec5SDimitry Andric LVComputationKind computation, 1510b57cec5SDimitry Andric bool IgnoreVarTypeLinkage = false); 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric LinkageInfo getLVForDecl(const NamedDecl *D, LVComputationKind computation); 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric LinkageInfo computeTypeLinkageInfo(const Type *T); computeTypeLinkageInfo(QualType T)1560b57cec5SDimitry Andric LinkageInfo computeTypeLinkageInfo(QualType T) { 1570b57cec5SDimitry Andric return computeTypeLinkageInfo(T.getTypePtr()); 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric LinkageInfo getDeclLinkageAndVisibility(const NamedDecl *D); 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric LinkageInfo getTypeLinkageAndVisibility(const Type *T); getTypeLinkageAndVisibility(QualType T)1630b57cec5SDimitry Andric LinkageInfo getTypeLinkageAndVisibility(QualType T) { 1640b57cec5SDimitry Andric return getTypeLinkageAndVisibility(T.getTypePtr()); 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric }; 1670b57cec5SDimitry Andric } // namespace clang 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric #endif 170