DelayedDiagnostic.h revision 00bd44d5677783527d7517c1ffe45e4d75a0f56f
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// This file defines the DelayedDiagnostic class, which is used to 11// record diagnostics that are being conditionally produced during 12// declarator parsing. Certain kinds of diagnostics --- notably 13// deprecation and access control --- are suppressed based on 14// semantic properties of the parsed declaration that aren't known 15// until it is fully parsed. 16// 17// This file also defines AccessedEntity. 18// 19//===----------------------------------------------------------------------===// 20 21#ifndef LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H 22#define LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H 23 24#include "clang/AST/DeclCXX.h" 25#include "clang/Basic/PartialDiagnostic.h" 26 27namespace clang { 28namespace sema { 29 30/// A declaration being accessed, together with information about how 31/// it was accessed. 32class AccessedEntity { 33public: 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(ASTContext &Context, 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, Context.getDiagAllocator()) { 52 } 53 54 AccessedEntity(ASTContext &Context, 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, Context.getDiagAllocator()) { 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 103private: 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. 114class DelayedDiagnostic { 115public: 116 enum DDKind { Deprecation, 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 makeDeprecation(SourceLocation Loc, 126 const NamedDecl *D, 127 StringRef Msg); 128 129 static DelayedDiagnostic makeAccess(SourceLocation Loc, 130 const AccessedEntity &Entity) { 131 DelayedDiagnostic DD; 132 DD.Kind = Access; 133 DD.Triggered = false; 134 DD.Loc = Loc; 135 new (&DD.getAccessData()) AccessedEntity(Entity); 136 return DD; 137 } 138 139 static DelayedDiagnostic makeForbiddenType(SourceLocation loc, 140 unsigned diagnostic, 141 QualType type, 142 unsigned argument) { 143 DelayedDiagnostic DD; 144 DD.Kind = ForbiddenType; 145 DD.Triggered = false; 146 DD.Loc = loc; 147 DD.ForbiddenTypeData.Diagnostic = diagnostic; 148 DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr(); 149 DD.ForbiddenTypeData.Argument = argument; 150 return DD; 151 } 152 153 AccessedEntity &getAccessData() { 154 assert(Kind == Access && "Not an access diagnostic."); 155 return *reinterpret_cast<AccessedEntity*>(AccessData); 156 } 157 const AccessedEntity &getAccessData() const { 158 assert(Kind == Access && "Not an access diagnostic."); 159 return *reinterpret_cast<const AccessedEntity*>(AccessData); 160 } 161 162 const NamedDecl *getDeprecationDecl() const { 163 assert(Kind == Deprecation && "Not a deprecation diagnostic."); 164 return DeprecationData.Decl; 165 } 166 167 StringRef getDeprecationMessage() const { 168 assert(Kind == Deprecation && "Not a deprecation diagnostic."); 169 return StringRef(DeprecationData.Message, 170 DeprecationData.MessageLen); 171 } 172 173 /// The diagnostic ID to emit. Used like so: 174 /// Diag(diag.Loc, diag.getForbiddenTypeDiagnostic()) 175 /// << diag.getForbiddenTypeOperand() 176 /// << diag.getForbiddenTypeArgument(); 177 unsigned getForbiddenTypeDiagnostic() const { 178 assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); 179 return ForbiddenTypeData.Diagnostic; 180 } 181 182 unsigned getForbiddenTypeArgument() const { 183 assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); 184 return ForbiddenTypeData.Argument; 185 } 186 187 QualType getForbiddenTypeOperand() const { 188 assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); 189 return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType); 190 } 191 192private: 193 union { 194 /// Deprecation. 195 struct { 196 const NamedDecl *Decl; 197 const char *Message; 198 size_t MessageLen; 199 } DeprecationData; 200 201 struct { 202 unsigned Diagnostic; 203 unsigned Argument; 204 void *OperandType; 205 } ForbiddenTypeData; 206 207 /// Access control. 208 char AccessData[sizeof(AccessedEntity)]; 209 }; 210}; 211 212} 213} 214 215#endif 216