1 //==- DependentDiagnostic.h - Dependently-generated diagnostics --*- C++ -*-==//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines interfaces for diagnostics which may or may
11 // fire based on how a template is instantiated.
12 //
13 // At the moment, the only consumer of this interface is access
14 // control.
15 //
16 //===----------------------------------------------------------------------===//
17
18 #ifndef LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H
19 #define LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H
20
21 #include "clang/AST/DeclBase.h"
22 #include "clang/AST/DeclContextInternals.h"
23 #include "clang/AST/Type.h"
24 #include "clang/Basic/PartialDiagnostic.h"
25 #include "clang/Basic/SourceLocation.h"
26 #include "clang/Basic/Specifiers.h"
27 #include <cassert>
28 #include <iterator>
29
30 namespace clang {
31
32 class ASTContext;
33 class CXXRecordDecl;
34 class NamedDecl;
35
36 /// A dependently-generated diagnostic.
37 class DependentDiagnostic {
38 public:
39 enum AccessNonce { Access = 0 };
40
Create(ASTContext & Context,DeclContext * Parent,AccessNonce _,SourceLocation Loc,bool IsMemberAccess,AccessSpecifier AS,NamedDecl * TargetDecl,CXXRecordDecl * NamingClass,QualType BaseObjectType,const PartialDiagnostic & PDiag)41 static DependentDiagnostic *Create(ASTContext &Context,
42 DeclContext *Parent,
43 AccessNonce _,
44 SourceLocation Loc,
45 bool IsMemberAccess,
46 AccessSpecifier AS,
47 NamedDecl *TargetDecl,
48 CXXRecordDecl *NamingClass,
49 QualType BaseObjectType,
50 const PartialDiagnostic &PDiag) {
51 DependentDiagnostic *DD = Create(Context, Parent, PDiag);
52 DD->AccessData.Loc = Loc.getRawEncoding();
53 DD->AccessData.IsMember = IsMemberAccess;
54 DD->AccessData.Access = AS;
55 DD->AccessData.TargetDecl = TargetDecl;
56 DD->AccessData.NamingClass = NamingClass;
57 DD->AccessData.BaseObjectType = BaseObjectType.getAsOpaquePtr();
58 return DD;
59 }
60
getKind()61 unsigned getKind() const {
62 return Access;
63 }
64
isAccessToMember()65 bool isAccessToMember() const {
66 assert(getKind() == Access);
67 return AccessData.IsMember;
68 }
69
getAccess()70 AccessSpecifier getAccess() const {
71 assert(getKind() == Access);
72 return AccessSpecifier(AccessData.Access);
73 }
74
getAccessLoc()75 SourceLocation getAccessLoc() const {
76 assert(getKind() == Access);
77 return SourceLocation::getFromRawEncoding(AccessData.Loc);
78 }
79
getAccessTarget()80 NamedDecl *getAccessTarget() const {
81 assert(getKind() == Access);
82 return AccessData.TargetDecl;
83 }
84
getAccessNamingClass()85 NamedDecl *getAccessNamingClass() const {
86 assert(getKind() == Access);
87 return AccessData.NamingClass;
88 }
89
getAccessBaseObjectType()90 QualType getAccessBaseObjectType() const {
91 assert(getKind() == Access);
92 return QualType::getFromOpaquePtr(AccessData.BaseObjectType);
93 }
94
getDiagnostic()95 const PartialDiagnostic &getDiagnostic() const {
96 return Diag;
97 }
98
99 private:
100 friend class DeclContext::ddiag_iterator;
101 friend class DependentStoredDeclsMap;
102
DependentDiagnostic(const PartialDiagnostic & PDiag,PartialDiagnostic::Storage * Storage)103 DependentDiagnostic(const PartialDiagnostic &PDiag,
104 PartialDiagnostic::Storage *Storage)
105 : Diag(PDiag, Storage) {}
106
107 static DependentDiagnostic *Create(ASTContext &Context,
108 DeclContext *Parent,
109 const PartialDiagnostic &PDiag);
110
111 DependentDiagnostic *NextDiagnostic;
112
113 PartialDiagnostic Diag;
114
115 struct {
116 unsigned Loc;
117 unsigned Access : 2;
118 unsigned IsMember : 1;
119 NamedDecl *TargetDecl;
120 CXXRecordDecl *NamingClass;
121 void *BaseObjectType;
122 } AccessData;
123 };
124
125 /// An iterator over the dependent diagnostics in a dependent context.
126 class DeclContext::ddiag_iterator {
127 public:
128 ddiag_iterator() = default;
ddiag_iterator(DependentDiagnostic * Ptr)129 explicit ddiag_iterator(DependentDiagnostic *Ptr) : Ptr(Ptr) {}
130
131 using value_type = DependentDiagnostic *;
132 using reference = DependentDiagnostic *;
133 using pointer = DependentDiagnostic *;
134 using difference_type = int;
135 using iterator_category = std::forward_iterator_tag;
136
137 reference operator*() const { return Ptr; }
138
139 ddiag_iterator &operator++() {
140 assert(Ptr && "attempt to increment past end of diag list");
141 Ptr = Ptr->NextDiagnostic;
142 return *this;
143 }
144
145 ddiag_iterator operator++(int) {
146 ddiag_iterator tmp = *this;
147 ++*this;
148 return tmp;
149 }
150
151 bool operator==(ddiag_iterator Other) const {
152 return Ptr == Other.Ptr;
153 }
154
155 bool operator!=(ddiag_iterator Other) const {
156 return Ptr != Other.Ptr;
157 }
158
159 ddiag_iterator &operator+=(difference_type N) {
160 assert(N >= 0 && "cannot rewind a DeclContext::ddiag_iterator");
161 while (N--)
162 ++*this;
163 return *this;
164 }
165
166 ddiag_iterator operator+(difference_type N) const {
167 ddiag_iterator tmp = *this;
168 tmp += N;
169 return tmp;
170 }
171
172 private:
173 DependentDiagnostic *Ptr = nullptr;
174 };
175
ddiags()176 inline DeclContext::ddiag_range DeclContext::ddiags() const {
177 assert(isDependentContext()
178 && "cannot iterate dependent diagnostics of non-dependent context");
179 const DependentStoredDeclsMap *Map
180 = static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->getLookupPtr());
181
182 if (!Map)
183 // Return an empty range using the always-end default constructor.
184 return ddiag_range(ddiag_iterator(), ddiag_iterator());
185
186 return ddiag_range(ddiag_iterator(Map->FirstDiagnostic), ddiag_iterator());
187 }
188
189 } // namespace clang
190
191 #endif // LLVM_CLANG_AST_DEPENDENTDIAGNOSTIC_H
192