1212795Sdim//===--- DelayedDiagnostic.h - Delayed declarator diagnostics ---*- C++ -*-===// 2212795Sdim// 3212795Sdim// The LLVM Compiler Infrastructure 4212795Sdim// 5212795Sdim// This file is distributed under the University of Illinois Open Source 6212795Sdim// License. See LICENSE.TXT for details. 7212795Sdim// 8212795Sdim//===----------------------------------------------------------------------===// 9212795Sdim// 10212795Sdim// This file defines the DelayedDiagnostic class, which is used to 11212795Sdim// record diagnostics that are being conditionally produced during 12212795Sdim// declarator parsing. Certain kinds of diagnostics --- notably 13212795Sdim// deprecation and access control --- are suppressed based on 14212795Sdim// semantic properties of the parsed declaration that aren't known 15212795Sdim// until it is fully parsed. 16212795Sdim// 17212795Sdim// This file also defines AccessedEntity. 18212795Sdim// 19212795Sdim//===----------------------------------------------------------------------===// 20212795Sdim 21212795Sdim#ifndef LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H 22212795Sdim#define LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H 23212795Sdim 24239462Sdim#include "clang/Sema/Sema.h" 25212795Sdim 26212795Sdimnamespace clang { 27212795Sdimnamespace sema { 28212795Sdim 29212795Sdim/// A declaration being accessed, together with information about how 30212795Sdim/// it was accessed. 31212795Sdimclass AccessedEntity { 32212795Sdimpublic: 33212795Sdim /// A member declaration found through lookup. The target is the 34212795Sdim /// member. 35212795Sdim enum MemberNonce { Member }; 36212795Sdim 37212795Sdim /// A hierarchy (base-to-derived or derived-to-base) conversion. 38212795Sdim /// The target is the base class. 39212795Sdim enum BaseNonce { Base }; 40212795Sdim 41212795Sdim bool isMemberAccess() const { return IsMember; } 42212795Sdim 43239462Sdim AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator, 44212795Sdim MemberNonce _, 45212795Sdim CXXRecordDecl *NamingClass, 46212795Sdim DeclAccessPair FoundDecl, 47212795Sdim QualType BaseObjectType) 48212795Sdim : Access(FoundDecl.getAccess()), IsMember(true), 49212795Sdim Target(FoundDecl.getDecl()), NamingClass(NamingClass), 50239462Sdim BaseObjectType(BaseObjectType), Diag(0, Allocator) { 51212795Sdim } 52212795Sdim 53239462Sdim AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator, 54212795Sdim BaseNonce _, 55212795Sdim CXXRecordDecl *BaseClass, 56212795Sdim CXXRecordDecl *DerivedClass, 57212795Sdim AccessSpecifier Access) 58212795Sdim : Access(Access), IsMember(false), 59212795Sdim Target(BaseClass), 60212795Sdim NamingClass(DerivedClass), 61239462Sdim Diag(0, Allocator) { 62212795Sdim } 63212795Sdim 64212795Sdim bool isQuiet() const { return Diag.getDiagID() == 0; } 65212795Sdim 66212795Sdim AccessSpecifier getAccess() const { return AccessSpecifier(Access); } 67212795Sdim 68212795Sdim // These apply to member decls... 69212795Sdim NamedDecl *getTargetDecl() const { return Target; } 70212795Sdim CXXRecordDecl *getNamingClass() const { return NamingClass; } 71212795Sdim 72212795Sdim // ...and these apply to hierarchy conversions. 73212795Sdim CXXRecordDecl *getBaseClass() const { 74212795Sdim assert(!IsMember); return cast<CXXRecordDecl>(Target); 75212795Sdim } 76212795Sdim CXXRecordDecl *getDerivedClass() const { return NamingClass; } 77212795Sdim 78212795Sdim /// Retrieves the base object type, important when accessing 79212795Sdim /// an instance member. 80212795Sdim QualType getBaseObjectType() const { return BaseObjectType; } 81212795Sdim 82212795Sdim /// Sets a diagnostic to be performed. The diagnostic is given 83212795Sdim /// four (additional) arguments: 84212795Sdim /// %0 - 0 if the entity was private, 1 if protected 85212795Sdim /// %1 - the DeclarationName of the entity 86212795Sdim /// %2 - the TypeDecl type of the naming class 87212795Sdim /// %3 - the TypeDecl type of the declaring class 88212795Sdim void setDiag(const PartialDiagnostic &PDiag) { 89212795Sdim assert(isQuiet() && "partial diagnostic already defined"); 90212795Sdim Diag = PDiag; 91212795Sdim } 92212795Sdim PartialDiagnostic &setDiag(unsigned DiagID) { 93212795Sdim assert(isQuiet() && "partial diagnostic already defined"); 94212795Sdim assert(DiagID && "creating null diagnostic"); 95212795Sdim Diag.Reset(DiagID); 96212795Sdim return Diag; 97212795Sdim } 98212795Sdim const PartialDiagnostic &getDiag() const { 99212795Sdim return Diag; 100212795Sdim } 101212795Sdim 102212795Sdimprivate: 103212795Sdim unsigned Access : 2; 104218893Sdim unsigned IsMember : 1; 105212795Sdim NamedDecl *Target; 106212795Sdim CXXRecordDecl *NamingClass; 107212795Sdim QualType BaseObjectType; 108212795Sdim PartialDiagnostic Diag; 109212795Sdim}; 110212795Sdim 111212795Sdim/// A diagnostic message which has been conditionally emitted pending 112212795Sdim/// the complete parsing of the current declaration. 113212795Sdimclass DelayedDiagnostic { 114212795Sdimpublic: 115224145Sdim enum DDKind { Deprecation, Access, ForbiddenType }; 116212795Sdim 117212795Sdim unsigned char Kind; // actually a DDKind 118212795Sdim bool Triggered; 119212795Sdim 120212795Sdim SourceLocation Loc; 121212795Sdim 122221345Sdim void Destroy(); 123212795Sdim 124212795Sdim static DelayedDiagnostic makeDeprecation(SourceLocation Loc, 125234353Sdim const NamedDecl *D, 126234353Sdim const ObjCInterfaceDecl *UnknownObjCClass, 127243830Sdim const ObjCPropertyDecl *ObjCProperty, 128234353Sdim StringRef Msg); 129212795Sdim 130212795Sdim static DelayedDiagnostic makeAccess(SourceLocation Loc, 131212795Sdim const AccessedEntity &Entity) { 132212795Sdim DelayedDiagnostic DD; 133212795Sdim DD.Kind = Access; 134212795Sdim DD.Triggered = false; 135212795Sdim DD.Loc = Loc; 136212795Sdim new (&DD.getAccessData()) AccessedEntity(Entity); 137212795Sdim return DD; 138212795Sdim } 139212795Sdim 140224145Sdim static DelayedDiagnostic makeForbiddenType(SourceLocation loc, 141224145Sdim unsigned diagnostic, 142224145Sdim QualType type, 143224145Sdim unsigned argument) { 144224145Sdim DelayedDiagnostic DD; 145224145Sdim DD.Kind = ForbiddenType; 146224145Sdim DD.Triggered = false; 147224145Sdim DD.Loc = loc; 148224145Sdim DD.ForbiddenTypeData.Diagnostic = diagnostic; 149224145Sdim DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr(); 150224145Sdim DD.ForbiddenTypeData.Argument = argument; 151224145Sdim return DD; 152224145Sdim } 153224145Sdim 154212795Sdim AccessedEntity &getAccessData() { 155218893Sdim assert(Kind == Access && "Not an access diagnostic."); 156212795Sdim return *reinterpret_cast<AccessedEntity*>(AccessData); 157212795Sdim } 158212795Sdim const AccessedEntity &getAccessData() const { 159218893Sdim assert(Kind == Access && "Not an access diagnostic."); 160212795Sdim return *reinterpret_cast<const AccessedEntity*>(AccessData); 161212795Sdim } 162218893Sdim 163218893Sdim const NamedDecl *getDeprecationDecl() const { 164218893Sdim assert(Kind == Deprecation && "Not a deprecation diagnostic."); 165218893Sdim return DeprecationData.Decl; 166218893Sdim } 167218893Sdim 168226633Sdim StringRef getDeprecationMessage() const { 169218893Sdim assert(Kind == Deprecation && "Not a deprecation diagnostic."); 170226633Sdim return StringRef(DeprecationData.Message, 171218893Sdim DeprecationData.MessageLen); 172218893Sdim } 173218893Sdim 174224145Sdim /// The diagnostic ID to emit. Used like so: 175224145Sdim /// Diag(diag.Loc, diag.getForbiddenTypeDiagnostic()) 176224145Sdim /// << diag.getForbiddenTypeOperand() 177224145Sdim /// << diag.getForbiddenTypeArgument(); 178224145Sdim unsigned getForbiddenTypeDiagnostic() const { 179224145Sdim assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); 180224145Sdim return ForbiddenTypeData.Diagnostic; 181224145Sdim } 182224145Sdim 183224145Sdim unsigned getForbiddenTypeArgument() const { 184224145Sdim assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); 185224145Sdim return ForbiddenTypeData.Argument; 186224145Sdim } 187224145Sdim 188224145Sdim QualType getForbiddenTypeOperand() const { 189224145Sdim assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); 190224145Sdim return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType); 191224145Sdim } 192234353Sdim 193234353Sdim const ObjCInterfaceDecl *getUnknownObjCClass() const { 194234353Sdim return DeprecationData.UnknownObjCClass; 195234353Sdim } 196224145Sdim 197243830Sdim const ObjCPropertyDecl *getObjCProperty() const { 198243830Sdim return DeprecationData.ObjCProperty; 199243830Sdim } 200243830Sdim 201218893Sdimprivate: 202249423Sdim 203249423Sdim struct DD { 204249423Sdim const NamedDecl *Decl; 205249423Sdim const ObjCInterfaceDecl *UnknownObjCClass; 206249423Sdim const ObjCPropertyDecl *ObjCProperty; 207249423Sdim const char *Message; 208249423Sdim size_t MessageLen; 209249423Sdim }; 210249423Sdim 211249423Sdim struct FTD { 212249423Sdim unsigned Diagnostic; 213249423Sdim unsigned Argument; 214249423Sdim void *OperandType; 215249423Sdim }; 216249423Sdim 217218893Sdim union { 218249423Sdim /// Deprecation 219249423Sdim struct DD DeprecationData; 220249423Sdim struct FTD ForbiddenTypeData; 221218893Sdim 222218893Sdim /// Access control. 223218893Sdim char AccessData[sizeof(AccessedEntity)]; 224218893Sdim }; 225212795Sdim}; 226212795Sdim 227239462Sdim/// DelayedDiagnosticPool - A collection of diagnostics which were 228239462Sdim/// delayed. 229239462Sdimclass DelayedDiagnosticPool { 230239462Sdim const DelayedDiagnosticPool *Parent; 231249423Sdim SmallVector<DelayedDiagnostic, 4> Diagnostics; 232239462Sdim 233243830Sdim DelayedDiagnosticPool(const DelayedDiagnosticPool &) LLVM_DELETED_FUNCTION; 234243830Sdim void operator=(const DelayedDiagnosticPool &) LLVM_DELETED_FUNCTION; 235239462Sdimpublic: 236239462Sdim DelayedDiagnosticPool(const DelayedDiagnosticPool *parent) : Parent(parent) {} 237239462Sdim ~DelayedDiagnosticPool() { 238249423Sdim for (SmallVectorImpl<DelayedDiagnostic>::iterator 239239462Sdim i = Diagnostics.begin(), e = Diagnostics.end(); i != e; ++i) 240239462Sdim i->Destroy(); 241239462Sdim } 242239462Sdim 243239462Sdim const DelayedDiagnosticPool *getParent() const { return Parent; } 244239462Sdim 245239462Sdim /// Does this pool, or any of its ancestors, contain any diagnostics? 246239462Sdim bool empty() const { 247239462Sdim return (Diagnostics.empty() && (Parent == NULL || Parent->empty())); 248239462Sdim } 249239462Sdim 250239462Sdim /// Add a diagnostic to this pool. 251239462Sdim void add(const DelayedDiagnostic &diag) { 252239462Sdim Diagnostics.push_back(diag); 253239462Sdim } 254239462Sdim 255239462Sdim /// Steal the diagnostics from the given pool. 256239462Sdim void steal(DelayedDiagnosticPool &pool) { 257239462Sdim if (pool.Diagnostics.empty()) return; 258239462Sdim 259239462Sdim if (Diagnostics.empty()) { 260239462Sdim Diagnostics = llvm_move(pool.Diagnostics); 261239462Sdim } else { 262239462Sdim Diagnostics.append(pool.pool_begin(), pool.pool_end()); 263239462Sdim } 264239462Sdim pool.Diagnostics.clear(); 265239462Sdim } 266239462Sdim 267249423Sdim typedef SmallVectorImpl<DelayedDiagnostic>::const_iterator pool_iterator; 268239462Sdim pool_iterator pool_begin() const { return Diagnostics.begin(); } 269239462Sdim pool_iterator pool_end() const { return Diagnostics.end(); } 270239462Sdim bool pool_empty() const { return Diagnostics.empty(); } 271239462Sdim}; 272239462Sdim 273212795Sdim} 274239462Sdim 275239462Sdim/// Add a diagnostic to the current delay pool. 276239462Sdiminline void Sema::DelayedDiagnostics::add(const sema::DelayedDiagnostic &diag) { 277239462Sdim assert(shouldDelayDiagnostics() && "trying to delay without pool"); 278239462Sdim CurPool->add(diag); 279212795Sdim} 280212795Sdim 281239462Sdim 282239462Sdim} 283239462Sdim 284212795Sdim#endif 285