File indexing completed on 2026-05-10 08:37:00
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #ifndef LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H
0022 #define LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H
0023
0024 #include "clang/AST/DeclAccessPair.h"
0025 #include "clang/AST/DeclBase.h"
0026 #include "clang/AST/DeclCXX.h"
0027 #include "clang/AST/Type.h"
0028 #include "clang/Basic/LLVM.h"
0029 #include "clang/Basic/PartialDiagnostic.h"
0030 #include "clang/Basic/SourceLocation.h"
0031 #include "clang/Basic/Specifiers.h"
0032 #include "clang/Sema/Sema.h"
0033 #include "llvm/ADT/ArrayRef.h"
0034 #include "llvm/ADT/SmallVector.h"
0035 #include "llvm/ADT/StringRef.h"
0036 #include "llvm/Support/Casting.h"
0037 #include <cassert>
0038 #include <cstddef>
0039 #include <utility>
0040
0041 namespace clang {
0042
0043 class ObjCInterfaceDecl;
0044 class ObjCPropertyDecl;
0045
0046 namespace sema {
0047
0048
0049
0050 class AccessedEntity {
0051 public:
0052
0053
0054 enum MemberNonce { Member };
0055
0056
0057
0058 enum BaseNonce { Base };
0059
0060 AccessedEntity(PartialDiagnostic::DiagStorageAllocator &Allocator,
0061 MemberNonce _, CXXRecordDecl *NamingClass,
0062 DeclAccessPair FoundDecl, QualType BaseObjectType)
0063 : Access(FoundDecl.getAccess()), IsMember(true),
0064 Target(FoundDecl.getDecl()), NamingClass(NamingClass),
0065 BaseObjectType(BaseObjectType), Diag(0, Allocator) {}
0066
0067 AccessedEntity(PartialDiagnostic::DiagStorageAllocator &Allocator,
0068 BaseNonce _, CXXRecordDecl *BaseClass,
0069 CXXRecordDecl *DerivedClass, AccessSpecifier Access)
0070 : Access(Access), IsMember(false), Target(BaseClass),
0071 NamingClass(DerivedClass), Diag(0, Allocator) {}
0072
0073 bool isMemberAccess() const { return IsMember; }
0074
0075 bool isQuiet() const { return Diag.getDiagID() == 0; }
0076
0077 AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
0078
0079
0080 NamedDecl *getTargetDecl() const { return Target; }
0081 CXXRecordDecl *getNamingClass() const { return NamingClass; }
0082
0083
0084 CXXRecordDecl *getBaseClass() const {
0085 assert(!IsMember); return cast<CXXRecordDecl>(Target);
0086 }
0087 CXXRecordDecl *getDerivedClass() const { return NamingClass; }
0088
0089
0090
0091 QualType getBaseObjectType() const { return BaseObjectType; }
0092
0093
0094
0095
0096
0097
0098
0099 void setDiag(const PartialDiagnostic &PDiag) {
0100 assert(isQuiet() && "partial diagnostic already defined");
0101 Diag = PDiag;
0102 }
0103 PartialDiagnostic &setDiag(unsigned DiagID) {
0104 assert(isQuiet() && "partial diagnostic already defined");
0105 assert(DiagID && "creating null diagnostic");
0106 Diag.Reset(DiagID);
0107 return Diag;
0108 }
0109 const PartialDiagnostic &getDiag() const {
0110 return Diag;
0111 }
0112
0113 private:
0114 LLVM_PREFERRED_TYPE(AccessSpecifier)
0115 unsigned Access : 2;
0116 LLVM_PREFERRED_TYPE(bool)
0117 unsigned IsMember : 1;
0118 NamedDecl *Target;
0119 CXXRecordDecl *NamingClass;
0120 QualType BaseObjectType;
0121 PartialDiagnostic Diag;
0122 };
0123
0124
0125
0126 class DelayedDiagnostic {
0127 public:
0128 enum DDKind : unsigned char { Availability, Access, ForbiddenType };
0129
0130 DDKind Kind;
0131 bool Triggered;
0132
0133 SourceLocation Loc;
0134
0135 void Destroy();
0136
0137 static DelayedDiagnostic makeAvailability(AvailabilityResult AR,
0138 ArrayRef<SourceLocation> Locs,
0139 const NamedDecl *ReferringDecl,
0140 const NamedDecl *OffendingDecl,
0141 const ObjCInterfaceDecl *UnknownObjCClass,
0142 const ObjCPropertyDecl *ObjCProperty,
0143 StringRef Msg,
0144 bool ObjCPropertyAccess);
0145
0146 static DelayedDiagnostic makeAccess(SourceLocation Loc,
0147 const AccessedEntity &Entity) {
0148 DelayedDiagnostic DD;
0149 DD.Kind = Access;
0150 DD.Triggered = false;
0151 DD.Loc = Loc;
0152 new (&DD.getAccessData()) AccessedEntity(Entity);
0153 return DD;
0154 }
0155
0156 static DelayedDiagnostic makeForbiddenType(SourceLocation loc,
0157 unsigned diagnostic,
0158 QualType type,
0159 unsigned argument) {
0160 DelayedDiagnostic DD;
0161 DD.Kind = ForbiddenType;
0162 DD.Triggered = false;
0163 DD.Loc = loc;
0164 DD.ForbiddenTypeData.Diagnostic = diagnostic;
0165 DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr();
0166 DD.ForbiddenTypeData.Argument = argument;
0167 return DD;
0168 }
0169
0170 AccessedEntity &getAccessData() {
0171 assert(Kind == Access && "Not an access diagnostic.");
0172 return *reinterpret_cast<AccessedEntity*>(AccessData);
0173 }
0174 const AccessedEntity &getAccessData() const {
0175 assert(Kind == Access && "Not an access diagnostic.");
0176 return *reinterpret_cast<const AccessedEntity*>(AccessData);
0177 }
0178
0179 const NamedDecl *getAvailabilityReferringDecl() const {
0180 assert(Kind == Availability && "Not an availability diagnostic.");
0181 return AvailabilityData.ReferringDecl;
0182 }
0183
0184 const NamedDecl *getAvailabilityOffendingDecl() const {
0185 return AvailabilityData.OffendingDecl;
0186 }
0187
0188 StringRef getAvailabilityMessage() const {
0189 assert(Kind == Availability && "Not an availability diagnostic.");
0190 return StringRef(AvailabilityData.Message, AvailabilityData.MessageLen);
0191 }
0192
0193 ArrayRef<SourceLocation> getAvailabilitySelectorLocs() const {
0194 assert(Kind == Availability && "Not an availability diagnostic.");
0195 return llvm::ArrayRef(AvailabilityData.SelectorLocs,
0196 AvailabilityData.NumSelectorLocs);
0197 }
0198
0199 AvailabilityResult getAvailabilityResult() const {
0200 assert(Kind == Availability && "Not an availability diagnostic.");
0201 return AvailabilityData.AR;
0202 }
0203
0204
0205
0206
0207
0208 unsigned getForbiddenTypeDiagnostic() const {
0209 assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
0210 return ForbiddenTypeData.Diagnostic;
0211 }
0212
0213 unsigned getForbiddenTypeArgument() const {
0214 assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
0215 return ForbiddenTypeData.Argument;
0216 }
0217
0218 QualType getForbiddenTypeOperand() const {
0219 assert(Kind == ForbiddenType && "not a forbidden-type diagnostic");
0220 return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType);
0221 }
0222
0223 const ObjCInterfaceDecl *getUnknownObjCClass() const {
0224 return AvailabilityData.UnknownObjCClass;
0225 }
0226
0227 const ObjCPropertyDecl *getObjCProperty() const {
0228 return AvailabilityData.ObjCProperty;
0229 }
0230
0231 bool getObjCPropertyAccess() const {
0232 return AvailabilityData.ObjCPropertyAccess;
0233 }
0234
0235 private:
0236 struct AD {
0237 const NamedDecl *ReferringDecl;
0238 const NamedDecl *OffendingDecl;
0239 const ObjCInterfaceDecl *UnknownObjCClass;
0240 const ObjCPropertyDecl *ObjCProperty;
0241 const char *Message;
0242 size_t MessageLen;
0243 SourceLocation *SelectorLocs;
0244 size_t NumSelectorLocs;
0245 AvailabilityResult AR;
0246 bool ObjCPropertyAccess;
0247 };
0248
0249 struct FTD {
0250 unsigned Diagnostic;
0251 unsigned Argument;
0252 void *OperandType;
0253 };
0254
0255 union {
0256 struct AD AvailabilityData;
0257 struct FTD ForbiddenTypeData;
0258
0259
0260 char AccessData[sizeof(AccessedEntity)];
0261 };
0262 };
0263
0264
0265 class DelayedDiagnosticPool {
0266 const DelayedDiagnosticPool *Parent;
0267 SmallVector<DelayedDiagnostic, 4> Diagnostics;
0268
0269 public:
0270 DelayedDiagnosticPool(const DelayedDiagnosticPool *parent) : Parent(parent) {}
0271
0272 DelayedDiagnosticPool(const DelayedDiagnosticPool &) = delete;
0273 DelayedDiagnosticPool &operator=(const DelayedDiagnosticPool &) = delete;
0274
0275 DelayedDiagnosticPool(DelayedDiagnosticPool &&Other)
0276 : Parent(Other.Parent), Diagnostics(std::move(Other.Diagnostics)) {
0277 Other.Diagnostics.clear();
0278 }
0279
0280 DelayedDiagnosticPool &operator=(DelayedDiagnosticPool &&Other) {
0281 Parent = Other.Parent;
0282 Diagnostics = std::move(Other.Diagnostics);
0283 Other.Diagnostics.clear();
0284 return *this;
0285 }
0286
0287 ~DelayedDiagnosticPool() {
0288 for (SmallVectorImpl<DelayedDiagnostic>::iterator
0289 i = Diagnostics.begin(), e = Diagnostics.end(); i != e; ++i)
0290 i->Destroy();
0291 }
0292
0293 const DelayedDiagnosticPool *getParent() const { return Parent; }
0294
0295
0296 bool empty() const {
0297 return (Diagnostics.empty() && (!Parent || Parent->empty()));
0298 }
0299
0300
0301 void add(const DelayedDiagnostic &diag) {
0302 Diagnostics.push_back(diag);
0303 }
0304
0305
0306 void steal(DelayedDiagnosticPool &pool) {
0307 if (pool.Diagnostics.empty()) return;
0308
0309 if (Diagnostics.empty()) {
0310 Diagnostics = std::move(pool.Diagnostics);
0311 } else {
0312 Diagnostics.append(pool.pool_begin(), pool.pool_end());
0313 }
0314 pool.Diagnostics.clear();
0315 }
0316
0317 using pool_iterator = SmallVectorImpl<DelayedDiagnostic>::const_iterator;
0318
0319 pool_iterator pool_begin() const { return Diagnostics.begin(); }
0320 pool_iterator pool_end() const { return Diagnostics.end(); }
0321 bool pool_empty() const { return Diagnostics.empty(); }
0322 };
0323
0324 }
0325
0326
0327 inline void Sema::DelayedDiagnostics::add(const sema::DelayedDiagnostic &diag) {
0328 assert(shouldDelayDiagnostics() && "trying to delay without pool");
0329 CurPool->add(diag);
0330 }
0331
0332 }
0333
0334 #endif