1 //===--- DelayedDiagnostic.h - Delayed declarator 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 /// \file 11 /// \brief Defines the classes clang::DelayedDiagnostic and 12 /// clang::AccessedEntity. 13 /// 14 /// DelayedDiangostic is used to record diagnostics that are being 15 /// conditionally produced during declarator parsing. Certain kinds of 16 /// diagnostics -- notably deprecation and access control -- are suppressed 17 /// based on semantic properties of the parsed declaration that aren't known 18 /// until it is fully parsed. 19 /// 20 //===----------------------------------------------------------------------===// 21 22 #ifndef LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H 23 #define LLVM_CLANG_SEMA_DELAYEDDIAGNOSTIC_H 24 25 #include "clang/Sema/Sema.h" 26 27 namespace clang { 28 namespace sema { 29 30 /// A declaration being accessed, together with information about how 31 /// it was accessed. 32 class AccessedEntity { 33 public: 34 /// A member declaration found through lookup. The target is the 35 /// member. 36 enum MemberNonce { Member }; 37 38 /// A hierarchy (base-to-derived or derived-to-base) conversion. 39 /// The target is the base class. 40 enum BaseNonce { Base }; 41 42 bool isMemberAccess() const { return IsMember; } 43 44 AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator, 45 MemberNonce _, 46 CXXRecordDecl *NamingClass, 47 DeclAccessPair FoundDecl, 48 QualType BaseObjectType) 49 : Access(FoundDecl.getAccess()), IsMember(true), 50 Target(FoundDecl.getDecl()), NamingClass(NamingClass), 51 BaseObjectType(BaseObjectType), Diag(0, Allocator) { 52 } 53 54 AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator, 55 BaseNonce _, 56 CXXRecordDecl *BaseClass, 57 CXXRecordDecl *DerivedClass, 58 AccessSpecifier Access) 59 : Access(Access), IsMember(false), 60 Target(BaseClass), 61 NamingClass(DerivedClass), 62 Diag(0, Allocator) { 63 } 64 65 bool isQuiet() const { return Diag.getDiagID() == 0; } 66 67 AccessSpecifier getAccess() const { return AccessSpecifier(Access); } 68 69 // These apply to member decls... 70 NamedDecl *getTargetDecl() const { return Target; } 71 CXXRecordDecl *getNamingClass() const { return NamingClass; } 72 73 // ...and these apply to hierarchy conversions. 74 CXXRecordDecl *getBaseClass() const { 75 assert(!IsMember); return cast<CXXRecordDecl>(Target); 76 } 77 CXXRecordDecl *getDerivedClass() const { return NamingClass; } 78 79 /// Retrieves the base object type, important when accessing 80 /// an instance member. 81 QualType getBaseObjectType() const { return BaseObjectType; } 82 83 /// Sets a diagnostic to be performed. The diagnostic is given 84 /// four (additional) arguments: 85 /// %0 - 0 if the entity was private, 1 if protected 86 /// %1 - the DeclarationName of the entity 87 /// %2 - the TypeDecl type of the naming class 88 /// %3 - the TypeDecl type of the declaring class 89 void setDiag(const PartialDiagnostic &PDiag) { 90 assert(isQuiet() && "partial diagnostic already defined"); 91 Diag = PDiag; 92 } 93 PartialDiagnostic &setDiag(unsigned DiagID) { 94 assert(isQuiet() && "partial diagnostic already defined"); 95 assert(DiagID && "creating null diagnostic"); 96 Diag.Reset(DiagID); 97 return Diag; 98 } 99 const PartialDiagnostic &getDiag() const { 100 return Diag; 101 } 102 103 private: 104 unsigned Access : 2; 105 unsigned IsMember : 1; 106 NamedDecl *Target; 107 CXXRecordDecl *NamingClass; 108 QualType BaseObjectType; 109 PartialDiagnostic Diag; 110 }; 111 112 /// A diagnostic message which has been conditionally emitted pending 113 /// the complete parsing of the current declaration. 114 class DelayedDiagnostic { 115 public: 116 enum DDKind { Deprecation, Unavailable, Access, ForbiddenType }; 117 118 unsigned char Kind; // actually a DDKind 119 bool Triggered; 120 121 SourceLocation Loc; 122 123 void Destroy(); 124 125 static DelayedDiagnostic makeAvailability(Sema::AvailabilityDiagnostic AD, 126 SourceLocation Loc, 127 const NamedDecl *D, 128 const ObjCInterfaceDecl *UnknownObjCClass, 129 const ObjCPropertyDecl *ObjCProperty, 130 StringRef Msg, 131 bool ObjCPropertyAccess); 132 133 134 static DelayedDiagnostic makeAccess(SourceLocation Loc, 135 const AccessedEntity &Entity) { 136 DelayedDiagnostic DD; 137 DD.Kind = Access; 138 DD.Triggered = false; 139 DD.Loc = Loc; 140 new (&DD.getAccessData()) AccessedEntity(Entity); 141 return DD; 142 } 143 144 static DelayedDiagnostic makeForbiddenType(SourceLocation loc, 145 unsigned diagnostic, 146 QualType type, 147 unsigned argument) { 148 DelayedDiagnostic DD; 149 DD.Kind = ForbiddenType; 150 DD.Triggered = false; 151 DD.Loc = loc; 152 DD.ForbiddenTypeData.Diagnostic = diagnostic; 153 DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr(); 154 DD.ForbiddenTypeData.Argument = argument; 155 return DD; 156 } 157 158 AccessedEntity &getAccessData() { 159 assert(Kind == Access && "Not an access diagnostic."); 160 return *reinterpret_cast<AccessedEntity*>(AccessData); 161 } 162 const AccessedEntity &getAccessData() const { 163 assert(Kind == Access && "Not an access diagnostic."); 164 return *reinterpret_cast<const AccessedEntity*>(AccessData); 165 } 166 167 const NamedDecl *getDeprecationDecl() const { 168 assert((Kind == Deprecation || Kind == Unavailable) && 169 "Not a deprecation diagnostic."); 170 return DeprecationData.Decl; 171 } 172 173 StringRef getDeprecationMessage() const { 174 assert((Kind == Deprecation || Kind == Unavailable) && 175 "Not a deprecation diagnostic."); 176 return StringRef(DeprecationData.Message, 177 DeprecationData.MessageLen); 178 } 179 180 /// The diagnostic ID to emit. Used like so: 181 /// Diag(diag.Loc, diag.getForbiddenTypeDiagnostic()) 182 /// << diag.getForbiddenTypeOperand() 183 /// << diag.getForbiddenTypeArgument(); 184 unsigned getForbiddenTypeDiagnostic() const { 185 assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); 186 return ForbiddenTypeData.Diagnostic; 187 } 188 189 unsigned getForbiddenTypeArgument() const { 190 assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); 191 return ForbiddenTypeData.Argument; 192 } 193 194 QualType getForbiddenTypeOperand() const { 195 assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); 196 return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType); 197 } 198 199 const ObjCInterfaceDecl *getUnknownObjCClass() const { 200 return DeprecationData.UnknownObjCClass; 201 } 202 203 const ObjCPropertyDecl *getObjCProperty() const { 204 return DeprecationData.ObjCProperty; 205 } 206 207 bool getObjCPropertyAccess() const { 208 return DeprecationData.ObjCPropertyAccess; 209 } 210 211 private: 212 213 struct DD { 214 const NamedDecl *Decl; 215 const ObjCInterfaceDecl *UnknownObjCClass; 216 const ObjCPropertyDecl *ObjCProperty; 217 const char *Message; 218 size_t MessageLen; 219 bool ObjCPropertyAccess; 220 }; 221 222 struct FTD { 223 unsigned Diagnostic; 224 unsigned Argument; 225 void *OperandType; 226 }; 227 228 union { 229 /// Deprecation 230 struct DD DeprecationData; 231 struct FTD ForbiddenTypeData; 232 233 /// Access control. 234 char AccessData[sizeof(AccessedEntity)]; 235 }; 236 }; 237 238 /// \brief A collection of diagnostics which were delayed. 239 class DelayedDiagnosticPool { 240 const DelayedDiagnosticPool *Parent; 241 SmallVector<DelayedDiagnostic, 4> Diagnostics; 242 243 DelayedDiagnosticPool(const DelayedDiagnosticPool &) = delete; 244 void operator=(const DelayedDiagnosticPool &) = delete; 245 public: 246 DelayedDiagnosticPool(const DelayedDiagnosticPool *parent) : Parent(parent) {} 247 ~DelayedDiagnosticPool() { 248 for (SmallVectorImpl<DelayedDiagnostic>::iterator 249 i = Diagnostics.begin(), e = Diagnostics.end(); i != e; ++i) 250 i->Destroy(); 251 } 252 253 DelayedDiagnosticPool(DelayedDiagnosticPool &&Other) 254 : Parent(Other.Parent), Diagnostics(std::move(Other.Diagnostics)) { 255 Other.Diagnostics.clear(); 256 } 257 DelayedDiagnosticPool &operator=(DelayedDiagnosticPool &&Other) { 258 Parent = Other.Parent; 259 Diagnostics = std::move(Other.Diagnostics); 260 Other.Diagnostics.clear(); 261 return *this; 262 } 263 264 const DelayedDiagnosticPool *getParent() const { return Parent; } 265 266 /// Does this pool, or any of its ancestors, contain any diagnostics? 267 bool empty() const { 268 return (Diagnostics.empty() && (!Parent || Parent->empty())); 269 } 270 271 /// Add a diagnostic to this pool. 272 void add(const DelayedDiagnostic &diag) { 273 Diagnostics.push_back(diag); 274 } 275 276 /// Steal the diagnostics from the given pool. 277 void steal(DelayedDiagnosticPool &pool) { 278 if (pool.Diagnostics.empty()) return; 279 280 if (Diagnostics.empty()) { 281 Diagnostics = std::move(pool.Diagnostics); 282 } else { 283 Diagnostics.append(pool.pool_begin(), pool.pool_end()); 284 } 285 pool.Diagnostics.clear(); 286 } 287 288 typedef SmallVectorImpl<DelayedDiagnostic>::const_iterator pool_iterator; 289 pool_iterator pool_begin() const { return Diagnostics.begin(); } 290 pool_iterator pool_end() const { return Diagnostics.end(); } 291 bool pool_empty() const { return Diagnostics.empty(); } 292 }; 293 294 } 295 296 /// Add a diagnostic to the current delay pool. 297 inline void Sema::DelayedDiagnostics::add(const sema::DelayedDiagnostic &diag) { 298 assert(shouldDelayDiagnostics() && "trying to delay without pool"); 299 CurPool->add(diag); 300 } 301 302 303 } 304 305 #endif 306