1//===----- Linkage.h - Linkage calculation-related utilities ----*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file provides AST-internal utilities for linkage and visibility
10// calculation.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_LIB_AST_LINKAGE_H
15#define LLVM_CLANG_LIB_AST_LINKAGE_H
16
17#include "clang/AST/ASTFwd.h"
18#include "clang/AST/Decl.h"
19#include "clang/AST/DeclCXX.h"
20#include "clang/AST/Type.h"
21#include "llvm/ADT/DenseMap.h"
22#include "llvm/ADT/PointerIntPair.h"
23#include <optional>
24
25namespace clang {
26/// Kinds of LV computation. The linkage side of the computation is
27/// always the same, but different things can change how visibility is
28/// computed.
29struct LVComputationKind {
30 /// The kind of entity whose visibility is ultimately being computed;
31 /// visibility computations for types and non-types follow different rules.
32 LLVM_PREFERRED_TYPE(bool)
33 unsigned ExplicitKind : 1;
34 /// Whether explicit visibility attributes should be ignored. When set,
35 /// visibility may only be restricted by the visibility of template arguments.
36 LLVM_PREFERRED_TYPE(bool)
37 unsigned IgnoreExplicitVisibility : 1;
38 /// Whether all visibility should be ignored. When set, we're only interested
39 /// in computing linkage.
40 LLVM_PREFERRED_TYPE(bool)
41 unsigned IgnoreAllVisibility : 1;
42
43 enum { NumLVComputationKindBits = 3 };
44
45 explicit LVComputationKind(NamedDecl::ExplicitVisibilityKind EK)
46 : ExplicitKind(EK), IgnoreExplicitVisibility(false),
47 IgnoreAllVisibility(false) {}
48
49 NamedDecl::ExplicitVisibilityKind getExplicitVisibilityKind() const {
50 return static_cast<NamedDecl::ExplicitVisibilityKind>(ExplicitKind);
51 }
52
53 bool isTypeVisibility() const {
54 return getExplicitVisibilityKind() == NamedDecl::VisibilityForType;
55 }
56 bool isValueVisibility() const {
57 return getExplicitVisibilityKind() == NamedDecl::VisibilityForValue;
58 }
59
60 /// Do an LV computation when we only care about the linkage.
61 static LVComputationKind forLinkageOnly() {
62 LVComputationKind Result(NamedDecl::VisibilityForValue);
63 Result.IgnoreExplicitVisibility = true;
64 Result.IgnoreAllVisibility = true;
65 return Result;
66 }
67
68 unsigned toBits() {
69 unsigned Bits = 0;
70 Bits = (Bits << 1) | ExplicitKind;
71 Bits = (Bits << 1) | IgnoreExplicitVisibility;
72 Bits = (Bits << 1) | IgnoreAllVisibility;
73 return Bits;
74 }
75};
76
77class LinkageComputer {
78 // We have a cache for repeated linkage/visibility computations. This saves us
79 // from exponential behavior in heavily templated code, such as:
80 //
81 // template <typename T, typename V> struct {};
82 // using A = int;
83 // using B = Foo<A, A>;
84 // using C = Foo<B, B>;
85 // using D = Foo<C, C>;
86 //
87 // The integer represents an LVComputationKind.
88 using QueryType =
89 llvm::PointerIntPair<const NamedDecl *,
90 LVComputationKind::NumLVComputationKindBits>;
91 llvm::SmallDenseMap<QueryType, LinkageInfo, 8> CachedLinkageInfo;
92
93 static QueryType makeCacheKey(const NamedDecl *ND, LVComputationKind Kind) {
94 return QueryType(ND, Kind.toBits());
95 }
96
97 std::optional<LinkageInfo> lookup(const NamedDecl *ND,
98 LVComputationKind Kind) const {
99 auto Iter = CachedLinkageInfo.find(Val: makeCacheKey(ND, Kind));
100 if (Iter == CachedLinkageInfo.end())
101 return std::nullopt;
102 return Iter->second;
103 }
104
105 void cache(const NamedDecl *ND, LVComputationKind Kind, LinkageInfo Info) {
106 CachedLinkageInfo[makeCacheKey(ND, Kind)] = Info;
107 }
108
109 LinkageInfo getLVForTemplateArgumentList(ArrayRef<TemplateArgument> Args,
110 LVComputationKind computation);
111
112 LinkageInfo getLVForTemplateArgumentList(const TemplateArgumentList &TArgs,
113 LVComputationKind computation);
114
115 void mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
116 const FunctionTemplateSpecializationInfo *specInfo,
117 LVComputationKind computation);
118
119 void mergeTemplateLV(LinkageInfo &LV,
120 const ClassTemplateSpecializationDecl *spec,
121 LVComputationKind computation);
122
123 void mergeTemplateLV(LinkageInfo &LV,
124 const VarTemplateSpecializationDecl *spec,
125 LVComputationKind computation);
126
127 LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
128 LVComputationKind computation,
129 bool IgnoreVarTypeLinkage);
130
131 LinkageInfo getLVForClassMember(const NamedDecl *D,
132 LVComputationKind computation,
133 bool IgnoreVarTypeLinkage);
134
135 LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl,
136 LVComputationKind computation);
137
138 LinkageInfo getLVForLocalDecl(const NamedDecl *D,
139 LVComputationKind computation);
140
141 LinkageInfo getLVForType(const Type &T, LVComputationKind computation);
142
143 LinkageInfo getLVForTemplateParameterList(const TemplateParameterList *Params,
144 LVComputationKind computation);
145
146 LinkageInfo getLVForValue(const APValue &V, LVComputationKind computation);
147
148public:
149 LinkageInfo computeLVForDecl(const NamedDecl *D,
150 LVComputationKind computation,
151 bool IgnoreVarTypeLinkage = false);
152
153 LinkageInfo getLVForDecl(const NamedDecl *D, LVComputationKind computation);
154
155 LinkageInfo computeTypeLinkageInfo(const Type *T);
156 LinkageInfo computeTypeLinkageInfo(QualType T) {
157 return computeTypeLinkageInfo(T: T.getTypePtr());
158 }
159
160 LinkageInfo getDeclLinkageAndVisibility(const NamedDecl *D);
161
162 LinkageInfo getTypeLinkageAndVisibility(const Type *T);
163 LinkageInfo getTypeLinkageAndVisibility(QualType T) {
164 return getTypeLinkageAndVisibility(T: T.getTypePtr());
165 }
166};
167} // namespace clang
168
169#endif
170