blob: e74c8f60c388b8705d3a3e6c53aecc684f91194a [file] [log] [blame]
Anders Carlsson4742a9c2009-03-27 05:05:05 +00001//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===//
Anders Carlsson8ed6f362009-03-27 04:43:36 +00002//
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 provides Sema routines for C++ access control semantics.
11//
12//===----------------------------------------------------------------------===//
Anders Carlsson17941122009-03-27 04:54:36 +000013
14#include "Sema.h"
John McCall553c0792010-01-23 00:46:32 +000015#include "Lookup.h"
Anders Carlsson733d77f2009-03-27 06:03:27 +000016#include "clang/AST/ASTContext.h"
Douglas Gregor36d1b142009-10-06 17:59:45 +000017#include "clang/AST/CXXInheritance.h"
18#include "clang/AST/DeclCXX.h"
John McCall16927f62010-03-12 01:19:31 +000019#include "clang/AST/DeclFriend.h"
John McCallc62bb642010-03-24 05:22:00 +000020#include "clang/AST/DependentDiagnostic.h"
John McCall58cc69d2010-01-27 01:50:18 +000021#include "clang/AST/ExprCXX.h"
22
Anders Carlsson17941122009-03-27 04:54:36 +000023using namespace clang;
24
Anders Carlsson4742a9c2009-03-27 05:05:05 +000025/// SetMemberAccessSpecifier - Set the access specifier of a member.
26/// Returns true on error (when the previous member decl access specifier
27/// is different from the new member decl access specifier).
Mike Stump11289f42009-09-09 15:08:12 +000028bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
Anders Carlsson17941122009-03-27 04:54:36 +000029 NamedDecl *PrevMemberDecl,
30 AccessSpecifier LexicalAS) {
31 if (!PrevMemberDecl) {
32 // Use the lexical access specifier.
33 MemberDecl->setAccess(LexicalAS);
34 return false;
35 }
Mike Stump11289f42009-09-09 15:08:12 +000036
Anders Carlsson17941122009-03-27 04:54:36 +000037 // C++ [class.access.spec]p3: When a member is redeclared its access
38 // specifier must be same as its initial declaration.
39 if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) {
Mike Stump11289f42009-09-09 15:08:12 +000040 Diag(MemberDecl->getLocation(),
41 diag::err_class_redeclared_with_different_access)
Anders Carlsson17941122009-03-27 04:54:36 +000042 << MemberDecl << LexicalAS;
43 Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)
44 << PrevMemberDecl << PrevMemberDecl->getAccess();
John McCall0a4bb262009-12-23 00:37:40 +000045
46 MemberDecl->setAccess(LexicalAS);
Anders Carlsson17941122009-03-27 04:54:36 +000047 return true;
48 }
Mike Stump11289f42009-09-09 15:08:12 +000049
Anders Carlsson17941122009-03-27 04:54:36 +000050 MemberDecl->setAccess(PrevMemberDecl->getAccess());
51 return false;
52}
Anders Carlsson4742a9c2009-03-27 05:05:05 +000053
John McCall5b0829a2010-02-10 09:31:12 +000054namespace {
55struct EffectiveContext {
John McCallc62bb642010-03-24 05:22:00 +000056 EffectiveContext() : Function(0), Dependent(false) {}
Anders Carlsson733d77f2009-03-27 06:03:27 +000057
John McCall5b0829a2010-02-10 09:31:12 +000058 explicit EffectiveContext(DeclContext *DC) {
John McCallc62bb642010-03-24 05:22:00 +000059 Dependent = DC->isDependentContext();
60
John McCall5b0829a2010-02-10 09:31:12 +000061 if (isa<FunctionDecl>(DC)) {
John McCall16927f62010-03-12 01:19:31 +000062 Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
John McCall5b0829a2010-02-10 09:31:12 +000063 DC = Function->getDeclContext();
64 } else
65 Function = 0;
John McCallfb803d72010-03-17 04:58:56 +000066
67 // C++ [class.access.nest]p1:
68 // A nested class is a member and as such has the same access
69 // rights as any other member.
70 // C++ [class.access]p2:
71 // A member of a class can also access all the names to which
72 // the class has access.
73 // This implies that the privileges of nesting are transitive.
74 while (isa<CXXRecordDecl>(DC)) {
75 CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
76 Records.push_back(Record);
77 DC = Record->getDeclContext();
78 }
Anders Carlsson733d77f2009-03-27 06:03:27 +000079 }
Sebastian Redle644e192009-07-18 14:32:15 +000080
John McCallc62bb642010-03-24 05:22:00 +000081 bool isDependent() const { return Dependent; }
82
John McCallfb803d72010-03-17 04:58:56 +000083 bool includesClass(const CXXRecordDecl *R) const {
84 R = R->getCanonicalDecl();
85 return std::find(Records.begin(), Records.end(), R)
86 != Records.end();
John McCall5b0829a2010-02-10 09:31:12 +000087 }
88
John McCallc62bb642010-03-24 05:22:00 +000089 DeclContext *getPrimaryContext() const {
90 assert((Function || !Records.empty()) && "context has no primary context");
91 if (Function) return Function;
92 return Records[0];
93 }
94
95 typedef llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;
96
John McCallfb803d72010-03-17 04:58:56 +000097 llvm::SmallVector<CXXRecordDecl*, 4> Records;
John McCall5b0829a2010-02-10 09:31:12 +000098 FunctionDecl *Function;
John McCallc62bb642010-03-24 05:22:00 +000099 bool Dependent;
John McCall5b0829a2010-02-10 09:31:12 +0000100};
Anders Carlsson4742a9c2009-03-27 05:05:05 +0000101}
John McCall553c0792010-01-23 00:46:32 +0000102
John McCall5b0829a2010-02-10 09:31:12 +0000103static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
104 CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
105 while (DeclaringClass->isAnonymousStructOrUnion())
106 DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
107 return DeclaringClass;
108}
109
John McCallc62bb642010-03-24 05:22:00 +0000110static bool MightInstantiateTo(Sema &S, DeclContext *Context,
111 DeclContext *Friend) {
112 if (Friend == Context)
113 return true;
114
115 assert(!Friend->isDependentContext() &&
116 "can't handle friends with dependent contexts here");
117
118 if (!Context->isDependentContext())
119 return false;
120
121 if (Friend->isFileContext())
122 return false;
123
124 // TODO: this is very conservative
125 return true;
126}
127
128// Asks whether the type in 'context' can ever instantiate to the type
129// in 'friend'.
130static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) {
131 if (Friend == Context)
132 return true;
133
134 if (!Friend->isDependentType() && !Context->isDependentType())
135 return false;
136
137 // TODO: this is very conservative.
138 return true;
139}
140
141static bool MightInstantiateTo(Sema &S,
142 FunctionDecl *Context,
143 FunctionDecl *Friend) {
144 if (Context->getDeclName() != Friend->getDeclName())
145 return false;
146
147 if (!MightInstantiateTo(S,
148 Context->getDeclContext(),
149 Friend->getDeclContext()))
150 return false;
151
152 CanQual<FunctionProtoType> FriendTy
153 = S.Context.getCanonicalType(Friend->getType())
154 ->getAs<FunctionProtoType>();
155 CanQual<FunctionProtoType> ContextTy
156 = S.Context.getCanonicalType(Context->getType())
157 ->getAs<FunctionProtoType>();
158
159 // There isn't any way that I know of to add qualifiers
160 // during instantiation.
161 if (FriendTy.getQualifiers() != ContextTy.getQualifiers())
162 return false;
163
164 if (FriendTy->getNumArgs() != ContextTy->getNumArgs())
165 return false;
166
167 if (!MightInstantiateTo(S,
168 ContextTy->getResultType(),
169 FriendTy->getResultType()))
170 return false;
171
172 for (unsigned I = 0, E = FriendTy->getNumArgs(); I != E; ++I)
173 if (!MightInstantiateTo(S,
174 ContextTy->getArgType(I),
175 FriendTy->getArgType(I)))
176 return false;
177
178 return true;
179}
180
181static bool MightInstantiateTo(Sema &S,
182 FunctionTemplateDecl *Context,
183 FunctionTemplateDecl *Friend) {
184 return MightInstantiateTo(S,
185 Context->getTemplatedDecl(),
186 Friend->getTemplatedDecl());
187}
188
John McCall39e82882010-03-17 20:01:29 +0000189static Sema::AccessResult MatchesFriend(Sema &S,
190 const EffectiveContext &EC,
191 const CXXRecordDecl *Friend) {
John McCall39e82882010-03-17 20:01:29 +0000192 if (EC.includesClass(Friend))
193 return Sema::AR_accessible;
194
John McCallc62bb642010-03-24 05:22:00 +0000195 if (EC.isDependent()) {
196 CanQualType FriendTy
197 = S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend));
198
199 for (EffectiveContext::record_iterator
200 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
201 CanQualType ContextTy
202 = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I));
203 if (MightInstantiateTo(S, ContextTy, FriendTy))
204 return Sema::AR_dependent;
205 }
206 }
207
John McCall39e82882010-03-17 20:01:29 +0000208 return Sema::AR_inaccessible;
209}
210
211static Sema::AccessResult MatchesFriend(Sema &S,
212 const EffectiveContext &EC,
John McCallc62bb642010-03-24 05:22:00 +0000213 CanQualType Friend) {
214 if (const RecordType *RT = Friend->getAs<RecordType>())
215 return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));
John McCall39e82882010-03-17 20:01:29 +0000216
John McCallc62bb642010-03-24 05:22:00 +0000217 // TODO: we can do better than this
218 if (Friend->isDependentType())
219 return Sema::AR_dependent;
John McCall39e82882010-03-17 20:01:29 +0000220
John McCallc62bb642010-03-24 05:22:00 +0000221 return Sema::AR_inaccessible;
222}
223
224/// Determines whether the given friend class template matches
225/// anything in the effective context.
226static Sema::AccessResult MatchesFriend(Sema &S,
227 const EffectiveContext &EC,
228 ClassTemplateDecl *Friend) {
229 Sema::AccessResult OnFailure = Sema::AR_inaccessible;
230
231 for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
232 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
233 CXXRecordDecl *Record = *I;
234
235 // Check whether the friend is the template of a class in the
236 // context chain. To do that, we need to figure out whether the
237 // current class has a template:
238 ClassTemplateDecl *CTD;
239
240 // A specialization of the template...
241 if (isa<ClassTemplateSpecializationDecl>(Record)) {
242 CTD = cast<ClassTemplateSpecializationDecl>(Record)
243 ->getSpecializedTemplate();
244
245 // ... or the template pattern itself.
246 } else {
247 CTD = Record->getDescribedClassTemplate();
248 if (!CTD) continue;
249 }
250
251 // It's a match.
252 if (Friend == CTD->getCanonicalDecl())
253 return Sema::AR_accessible;
254
255 // If the template names don't match, it can't be a dependent
256 // match. This isn't true in C++0x because of template aliases.
257 if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName())
258 continue;
259
260 // If the class's context can't instantiate to the friend's
261 // context, it can't be a dependent match.
262 if (!MightInstantiateTo(S, CTD->getDeclContext(),
263 Friend->getDeclContext()))
264 continue;
265
266 // Otherwise, it's a dependent match.
267 OnFailure = Sema::AR_dependent;
John McCall39e82882010-03-17 20:01:29 +0000268 }
269
John McCallc62bb642010-03-24 05:22:00 +0000270 return OnFailure;
271}
272
273/// Determines whether the given friend function matches anything in
274/// the effective context.
275static Sema::AccessResult MatchesFriend(Sema &S,
276 const EffectiveContext &EC,
277 FunctionDecl *Friend) {
278 if (!EC.Function)
279 return Sema::AR_inaccessible;
280
281 if (Friend == EC.Function)
282 return Sema::AR_accessible;
283
284 if (EC.isDependent() && MightInstantiateTo(S, EC.Function, Friend))
285 return Sema::AR_dependent;
286
287 return Sema::AR_inaccessible;
288}
289
290/// Determines whether the given friend function template matches
291/// anything in the effective context.
292static Sema::AccessResult MatchesFriend(Sema &S,
293 const EffectiveContext &EC,
294 FunctionTemplateDecl *Friend) {
295 if (!EC.Function) return Sema::AR_inaccessible;
296
297 FunctionTemplateDecl *FTD = EC.Function->getPrimaryTemplate();
298 if (!FTD)
299 FTD = EC.Function->getDescribedFunctionTemplate();
300 if (!FTD)
301 return Sema::AR_inaccessible;
302
303 if (Friend == FTD->getCanonicalDecl())
304 return Sema::AR_accessible;
305
306 if (MightInstantiateTo(S, FTD, Friend))
307 return Sema::AR_dependent;
308
309 return Sema::AR_inaccessible;
310}
311
312/// Determines whether the given friend declaration matches anything
313/// in the effective context.
314static Sema::AccessResult MatchesFriend(Sema &S,
315 const EffectiveContext &EC,
316 FriendDecl *FriendD) {
317 if (Type *T = FriendD->getFriendType())
318 return MatchesFriend(S, EC, T->getCanonicalTypeUnqualified());
319
320 NamedDecl *Friend
321 = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl());
John McCall39e82882010-03-17 20:01:29 +0000322
323 // FIXME: declarations with dependent or templated scope.
324
John McCallc62bb642010-03-24 05:22:00 +0000325 if (isa<ClassTemplateDecl>(Friend))
326 return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend));
John McCall39e82882010-03-17 20:01:29 +0000327
John McCallc62bb642010-03-24 05:22:00 +0000328 if (isa<FunctionTemplateDecl>(Friend))
329 return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend));
John McCall39e82882010-03-17 20:01:29 +0000330
John McCallc62bb642010-03-24 05:22:00 +0000331 if (isa<CXXRecordDecl>(Friend))
332 return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend));
John McCall39e82882010-03-17 20:01:29 +0000333
John McCallc62bb642010-03-24 05:22:00 +0000334 assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind");
335 return MatchesFriend(S, EC, cast<FunctionDecl>(Friend));
John McCall39e82882010-03-17 20:01:29 +0000336}
337
John McCall5b0829a2010-02-10 09:31:12 +0000338static Sema::AccessResult GetFriendKind(Sema &S,
339 const EffectiveContext &EC,
340 const CXXRecordDecl *Class) {
John McCall16927f62010-03-12 01:19:31 +0000341 // A class always has access to its own members.
John McCallfb803d72010-03-17 04:58:56 +0000342 if (EC.includesClass(Class))
John McCall5b0829a2010-02-10 09:31:12 +0000343 return Sema::AR_accessible;
344
John McCallfb803d72010-03-17 04:58:56 +0000345 Sema::AccessResult OnFailure = Sema::AR_inaccessible;
346
John McCall16927f62010-03-12 01:19:31 +0000347 // Okay, check friends.
348 for (CXXRecordDecl::friend_iterator I = Class->friend_begin(),
349 E = Class->friend_end(); I != E; ++I) {
350 FriendDecl *Friend = *I;
351
John McCall39e82882010-03-17 20:01:29 +0000352 switch (MatchesFriend(S, EC, Friend)) {
353 case Sema::AR_accessible:
354 return Sema::AR_accessible;
John McCall16927f62010-03-12 01:19:31 +0000355
John McCall39e82882010-03-17 20:01:29 +0000356 case Sema::AR_inaccessible:
357 break;
John McCallfb803d72010-03-17 04:58:56 +0000358
John McCall39e82882010-03-17 20:01:29 +0000359 case Sema::AR_dependent:
360 OnFailure = Sema::AR_dependent;
361 break;
362
363 case Sema::AR_delayed:
364 llvm_unreachable("cannot get delayed answer from MatchesFriend");
John McCall16927f62010-03-12 01:19:31 +0000365 }
John McCall16927f62010-03-12 01:19:31 +0000366 }
367
368 // That's it, give up.
John McCallfb803d72010-03-17 04:58:56 +0000369 return OnFailure;
John McCall5b0829a2010-02-10 09:31:12 +0000370}
371
372/// Finds the best path from the naming class to the declaring class,
373/// taking friend declarations into account.
374///
John McCalla332b952010-03-18 23:49:19 +0000375/// \param FinalAccess the access of the "final step", or AS_none if
376/// there is no final step.
John McCall5b0829a2010-02-10 09:31:12 +0000377/// \return null if friendship is dependent
378static CXXBasePath *FindBestPath(Sema &S,
379 const EffectiveContext &EC,
380 CXXRecordDecl *Derived,
381 CXXRecordDecl *Base,
John McCalla332b952010-03-18 23:49:19 +0000382 AccessSpecifier FinalAccess,
John McCall5b0829a2010-02-10 09:31:12 +0000383 CXXBasePaths &Paths) {
384 // Derive the paths to the desired base.
385 bool isDerived = Derived->isDerivedFrom(Base, Paths);
386 assert(isDerived && "derived class not actually derived from base");
387 (void) isDerived;
388
389 CXXBasePath *BestPath = 0;
390
John McCalla332b952010-03-18 23:49:19 +0000391 assert(FinalAccess != AS_none && "forbidden access after declaring class");
392
John McCallc62bb642010-03-24 05:22:00 +0000393 bool AnyDependent = false;
394
John McCall5b0829a2010-02-10 09:31:12 +0000395 // Derive the friend-modified access along each path.
396 for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
397 PI != PE; ++PI) {
398
399 // Walk through the path backwards.
John McCalla332b952010-03-18 23:49:19 +0000400 AccessSpecifier PathAccess = FinalAccess;
John McCall5b0829a2010-02-10 09:31:12 +0000401 CXXBasePath::iterator I = PI->end(), E = PI->begin();
402 while (I != E) {
403 --I;
404
John McCalla332b952010-03-18 23:49:19 +0000405 assert(PathAccess != AS_none);
406
407 // If the declaration is a private member of a base class, there
408 // is no level of friendship in derived classes that can make it
409 // accessible.
410 if (PathAccess == AS_private) {
411 PathAccess = AS_none;
412 break;
413 }
414
John McCall5b0829a2010-02-10 09:31:12 +0000415 AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
416 if (BaseAccess != AS_public) {
417 switch (GetFriendKind(S, EC, I->Class)) {
John McCalla332b952010-03-18 23:49:19 +0000418 case Sema::AR_inaccessible:
419 PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess);
420 break;
421 case Sema::AR_accessible:
422 PathAccess = AS_public;
423 break;
424 case Sema::AR_dependent:
John McCallc62bb642010-03-24 05:22:00 +0000425 AnyDependent = true;
426 goto Next;
John McCall5b0829a2010-02-10 09:31:12 +0000427 case Sema::AR_delayed:
428 llvm_unreachable("friend resolution is never delayed"); break;
429 }
430 }
John McCall5b0829a2010-02-10 09:31:12 +0000431 }
432
433 // Note that we modify the path's Access field to the
434 // friend-modified access.
435 if (BestPath == 0 || PathAccess < BestPath->Access) {
436 BestPath = &*PI;
437 BestPath->Access = PathAccess;
John McCallc62bb642010-03-24 05:22:00 +0000438
439 // Short-circuit if we found a public path.
440 if (BestPath->Access == AS_public)
441 return BestPath;
John McCall5b0829a2010-02-10 09:31:12 +0000442 }
John McCallc62bb642010-03-24 05:22:00 +0000443
444 Next: ;
John McCall5b0829a2010-02-10 09:31:12 +0000445 }
446
John McCallc62bb642010-03-24 05:22:00 +0000447 assert((!BestPath || BestPath->Access != AS_public) &&
448 "fell out of loop with public path");
449
450 // We didn't find a public path, but at least one path was subject
451 // to dependent friendship, so delay the check.
452 if (AnyDependent)
453 return 0;
454
John McCall5b0829a2010-02-10 09:31:12 +0000455 return BestPath;
456}
457
458/// Diagnose the path which caused the given declaration or base class
459/// to become inaccessible.
460static void DiagnoseAccessPath(Sema &S,
461 const EffectiveContext &EC,
462 CXXRecordDecl *NamingClass,
463 CXXRecordDecl *DeclaringClass,
464 NamedDecl *D, AccessSpecifier Access) {
John McCall553c0792010-01-23 00:46:32 +0000465 // Easy case: the decl's natural access determined its path access.
John McCall5b0829a2010-02-10 09:31:12 +0000466 // We have to check against AS_private here in case Access is AS_none,
467 // indicating a non-public member of a private base class.
468 //
469 // DependentFriend should be impossible here.
470 if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
471 switch (GetFriendKind(S, EC, DeclaringClass)) {
472 case Sema::AR_inaccessible: {
473 S.Diag(D->getLocation(), diag::note_access_natural)
474 << (unsigned) (Access == AS_protected)
475 << /*FIXME: not implicitly*/ 0;
476 return;
477 }
478
479 case Sema::AR_accessible: break;
480
481 case Sema::AR_dependent:
482 case Sema::AR_delayed:
483 llvm_unreachable("dependent/delayed not allowed");
484 return;
485 }
486 }
487
488 CXXBasePaths Paths;
John McCalla332b952010-03-18 23:49:19 +0000489 CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass,
490 AS_public, Paths);
John McCall5b0829a2010-02-10 09:31:12 +0000491
492 CXXBasePath::iterator I = Path.end(), E = Path.begin();
493 while (I != E) {
494 --I;
495
496 const CXXBaseSpecifier *BS = I->Base;
497 AccessSpecifier BaseAccess = BS->getAccessSpecifier();
498
499 // If this is public inheritance, or the derived class is a friend,
500 // skip this step.
501 if (BaseAccess == AS_public)
502 continue;
503
504 switch (GetFriendKind(S, EC, I->Class)) {
505 case Sema::AR_accessible: continue;
506 case Sema::AR_inaccessible: break;
507
508 case Sema::AR_dependent:
509 case Sema::AR_delayed:
510 llvm_unreachable("dependent friendship, should not be diagnosing");
511 }
512
513 // Check whether this base specifier is the tighest point
514 // constraining access. We have to check against AS_private for
515 // the same reasons as above.
516 if (BaseAccess == AS_private || BaseAccess >= Access) {
517
518 // We're constrained by inheritance, but we want to say
519 // "declared private here" if we're diagnosing a hierarchy
520 // conversion and this is the final step.
521 unsigned diagnostic;
522 if (D) diagnostic = diag::note_access_constrained_by_path;
523 else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural;
524 else diagnostic = diag::note_access_constrained_by_path;
525
526 S.Diag(BS->getSourceRange().getBegin(), diagnostic)
527 << BS->getSourceRange()
528 << (BaseAccess == AS_protected)
529 << (BS->getAccessSpecifierAsWritten() == AS_none);
530 return;
531 }
532 }
533
534 llvm_unreachable("access not apparently constrained by path");
535}
536
537/// Diagnose an inaccessible class member.
538static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc,
539 const EffectiveContext &EC,
540 CXXRecordDecl *NamingClass,
541 AccessSpecifier Access,
542 const Sema::AccessedEntity &Entity) {
543 NamedDecl *D = Entity.getTargetDecl();
544 CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
545
John McCall1064d7e2010-03-16 05:22:47 +0000546 S.Diag(Loc, Entity.getDiag())
547 << (Access == AS_protected)
548 << D->getDeclName()
549 << S.Context.getTypeDeclType(NamingClass)
550 << S.Context.getTypeDeclType(DeclaringClass);
John McCall5b0829a2010-02-10 09:31:12 +0000551 DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
552}
553
554/// Diagnose an inaccessible hierarchy conversion.
555static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc,
556 const EffectiveContext &EC,
557 AccessSpecifier Access,
John McCall1064d7e2010-03-16 05:22:47 +0000558 const Sema::AccessedEntity &Entity) {
559 S.Diag(Loc, Entity.getDiag())
560 << (Access == AS_protected)
561 << DeclarationName()
562 << S.Context.getTypeDeclType(Entity.getDerivedClass())
563 << S.Context.getTypeDeclType(Entity.getBaseClass());
John McCall5b0829a2010-02-10 09:31:12 +0000564 DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
565 Entity.getBaseClass(), 0, Access);
566}
567
John McCall1064d7e2010-03-16 05:22:47 +0000568static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
John McCall5b0829a2010-02-10 09:31:12 +0000569 const EffectiveContext &EC,
570 CXXRecordDecl *NamingClass,
571 AccessSpecifier Access,
John McCall1064d7e2010-03-16 05:22:47 +0000572 const Sema::AccessedEntity &Entity) {
John McCall5b0829a2010-02-10 09:31:12 +0000573 if (Entity.isMemberAccess())
574 DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
575 else
John McCall1064d7e2010-03-16 05:22:47 +0000576 DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity);
John McCall5b0829a2010-02-10 09:31:12 +0000577}
578
579
580/// Try to elevate access using friend declarations. This is
581/// potentially quite expensive.
John McCallc62bb642010-03-24 05:22:00 +0000582///
583/// \return true if elevation was dependent
584static bool TryElevateAccess(Sema &S,
John McCall5b0829a2010-02-10 09:31:12 +0000585 const EffectiveContext &EC,
586 const Sema::AccessedEntity &Entity,
587 AccessSpecifier &Access) {
588 CXXRecordDecl *DeclaringClass;
589 if (Entity.isMemberAccess()) {
590 DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
591 } else {
592 DeclaringClass = Entity.getBaseClass();
593 }
594 CXXRecordDecl *NamingClass = Entity.getNamingClass();
595
596 // Adjust the declaration of the referred entity.
John McCalla332b952010-03-18 23:49:19 +0000597 AccessSpecifier DeclAccess = AS_public;
John McCall5b0829a2010-02-10 09:31:12 +0000598 if (Entity.isMemberAccess()) {
599 NamedDecl *Target = Entity.getTargetDecl();
600
601 DeclAccess = Target->getAccess();
602 if (DeclAccess != AS_public) {
603 switch (GetFriendKind(S, EC, DeclaringClass)) {
604 case Sema::AR_accessible: DeclAccess = AS_public; break;
605 case Sema::AR_inaccessible: break;
John McCallc62bb642010-03-24 05:22:00 +0000606 case Sema::AR_dependent: return true;
John McCall5b0829a2010-02-10 09:31:12 +0000607 case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
608 }
609 }
610
611 if (DeclaringClass == NamingClass) {
612 Access = DeclAccess;
John McCallc62bb642010-03-24 05:22:00 +0000613 return false;
John McCall5b0829a2010-02-10 09:31:12 +0000614 }
615 }
616
617 assert(DeclaringClass != NamingClass);
618
619 // Append the declaration's access if applicable.
620 CXXBasePaths Paths;
621 CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(),
John McCalla332b952010-03-18 23:49:19 +0000622 DeclaringClass, DeclAccess, Paths);
John McCallc62bb642010-03-24 05:22:00 +0000623 if (!Path)
624 return true;
John McCall553c0792010-01-23 00:46:32 +0000625
John McCalla332b952010-03-18 23:49:19 +0000626 // Grab the access along the best path (note that this includes the
627 // final-step access).
John McCall5b0829a2010-02-10 09:31:12 +0000628 AccessSpecifier NewAccess = Path->Access;
John McCall5b0829a2010-02-10 09:31:12 +0000629 assert(NewAccess <= Access && "access along best path worse than direct?");
630 Access = NewAccess;
John McCallc62bb642010-03-24 05:22:00 +0000631 return false;
632}
633
634static void DelayAccess(Sema &S,
635 const EffectiveContext &EC,
636 SourceLocation Loc,
637 const Sema::AccessedEntity &Entity) {
638 assert(EC.isDependent() && "delaying non-dependent access");
639 DeclContext *DC = EC.getPrimaryContext();
640 assert(DC->isDependentContext() && "delaying non-dependent access");
641 DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access,
642 Loc,
643 Entity.isMemberAccess(),
644 Entity.getAccess(),
645 Entity.getTargetDecl(),
646 Entity.getNamingClass(),
647 Entity.getDiag());
John McCall553c0792010-01-23 00:46:32 +0000648}
649
John McCall5b0829a2010-02-10 09:31:12 +0000650/// Checks access to an entity from the given effective context.
651static Sema::AccessResult CheckEffectiveAccess(Sema &S,
652 const EffectiveContext &EC,
653 SourceLocation Loc,
John McCall1064d7e2010-03-16 05:22:47 +0000654 Sema::AccessedEntity const &Entity) {
John McCall5b0829a2010-02-10 09:31:12 +0000655 AccessSpecifier Access = Entity.getAccess();
John McCallfb803d72010-03-17 04:58:56 +0000656 assert(Access != AS_public && "called for public access!");
John McCall553c0792010-01-23 00:46:32 +0000657
John McCallfb803d72010-03-17 04:58:56 +0000658 // Find a non-anonymous naming class. For records with access,
659 // there should always be one of these.
John McCall5b0829a2010-02-10 09:31:12 +0000660 CXXRecordDecl *NamingClass = Entity.getNamingClass();
John McCall553c0792010-01-23 00:46:32 +0000661 while (NamingClass->isAnonymousStructOrUnion())
John McCall1064d7e2010-03-16 05:22:47 +0000662 NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
John McCall553c0792010-01-23 00:46:32 +0000663
John McCallfb803d72010-03-17 04:58:56 +0000664 // White-list accesses from classes with privileges equivalent to the
665 // naming class --- but only if the access path isn't forbidden
666 // (i.e. an access of a private member from a subclass).
667 if (Access != AS_none && EC.includesClass(NamingClass))
John McCall5b0829a2010-02-10 09:31:12 +0000668 return Sema::AR_accessible;
John McCallfb803d72010-03-17 04:58:56 +0000669
670 // Try to elevate access.
John McCallfb803d72010-03-17 04:58:56 +0000671 // TODO: on some code, it might be better to do the protected check
672 // without trying to elevate first.
John McCallc62bb642010-03-24 05:22:00 +0000673 if (TryElevateAccess(S, EC, Entity, Access)) {
674 DelayAccess(S, EC, Loc, Entity);
675 return Sema::AR_dependent;
676 }
677
John McCallfb803d72010-03-17 04:58:56 +0000678 if (Access == AS_public) return Sema::AR_accessible;
John McCall553c0792010-01-23 00:46:32 +0000679
680 // Protected access.
681 if (Access == AS_protected) {
682 // FIXME: implement [class.protected]p1
John McCallfb803d72010-03-17 04:58:56 +0000683 for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
684 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I)
685 if ((*I)->isDerivedFrom(NamingClass))
686 return Sema::AR_accessible;
John McCall553c0792010-01-23 00:46:32 +0000687
John McCallfb803d72010-03-17 04:58:56 +0000688 // FIXME: delay if we can't decide class derivation yet.
John McCall553c0792010-01-23 00:46:32 +0000689 }
690
John McCall5b0829a2010-02-10 09:31:12 +0000691 // Okay, that's it, reject it.
John McCall1064d7e2010-03-16 05:22:47 +0000692 if (!Entity.isQuiet())
693 DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
John McCall5b0829a2010-02-10 09:31:12 +0000694 return Sema::AR_inaccessible;
695}
John McCall553c0792010-01-23 00:46:32 +0000696
John McCall5b0829a2010-02-10 09:31:12 +0000697static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
John McCall1064d7e2010-03-16 05:22:47 +0000698 const Sema::AccessedEntity &Entity) {
John McCall5b0829a2010-02-10 09:31:12 +0000699 // If the access path is public, it's accessible everywhere.
700 if (Entity.getAccess() == AS_public)
701 return Sema::AR_accessible;
John McCall553c0792010-01-23 00:46:32 +0000702
John McCall5b0829a2010-02-10 09:31:12 +0000703 // If we're currently parsing a top-level declaration, delay
704 // diagnostics. This is the only case where parsing a declaration
705 // can actually change our effective context for the purposes of
706 // access control.
707 if (S.CurContext->isFileContext() && S.ParsingDeclDepth) {
John McCall5b0829a2010-02-10 09:31:12 +0000708 S.DelayedDiagnostics.push_back(
709 Sema::DelayedDiagnostic::makeAccess(Loc, Entity));
710 return Sema::AR_delayed;
John McCall553c0792010-01-23 00:46:32 +0000711 }
712
John McCall5b0829a2010-02-10 09:31:12 +0000713 return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
John McCall1064d7e2010-03-16 05:22:47 +0000714 Loc, Entity);
John McCall553c0792010-01-23 00:46:32 +0000715}
716
John McCall86121512010-01-27 03:50:35 +0000717void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
John McCall86121512010-01-27 03:50:35 +0000718 // Pretend we did this from the context of the newly-parsed
719 // declaration.
John McCall5b0829a2010-02-10 09:31:12 +0000720 EffectiveContext EC(Ctx->getDeclContext());
John McCall86121512010-01-27 03:50:35 +0000721
John McCall1064d7e2010-03-16 05:22:47 +0000722 if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData()))
John McCall86121512010-01-27 03:50:35 +0000723 DD.Triggered = true;
724}
725
John McCallc62bb642010-03-24 05:22:00 +0000726void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,
727 const MultiLevelTemplateArgumentList &TemplateArgs) {
728 SourceLocation Loc = DD.getAccessLoc();
729 AccessSpecifier Access = DD.getAccess();
730
731 Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(),
732 TemplateArgs);
733 if (!NamingD) return;
734 Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(),
735 TemplateArgs);
736 if (!TargetD) return;
737
738 if (DD.isAccessToMember()) {
739 AccessedEntity Entity(AccessedEntity::Member,
740 cast<CXXRecordDecl>(NamingD),
741 Access,
742 cast<NamedDecl>(TargetD));
743 Entity.setDiag(DD.getDiagnostic());
744 CheckAccess(*this, Loc, Entity);
745 } else {
746 AccessedEntity Entity(AccessedEntity::Base,
747 cast<CXXRecordDecl>(TargetD),
748 cast<CXXRecordDecl>(NamingD),
749 Access);
750 Entity.setDiag(DD.getDiagnostic());
751 CheckAccess(*this, Loc, Entity);
752 }
753}
754
John McCall5b0829a2010-02-10 09:31:12 +0000755Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
John McCalla0296f72010-03-19 07:35:19 +0000756 DeclAccessPair Found) {
John McCall1064d7e2010-03-16 05:22:47 +0000757 if (!getLangOptions().AccessControl ||
758 !E->getNamingClass() ||
John McCalla0296f72010-03-19 07:35:19 +0000759 Found.getAccess() == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000760 return AR_accessible;
John McCall58cc69d2010-01-27 01:50:18 +0000761
John McCalla0296f72010-03-19 07:35:19 +0000762 AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found);
John McCall1064d7e2010-03-16 05:22:47 +0000763 Entity.setDiag(diag::err_access) << E->getSourceRange();
764
765 return CheckAccess(*this, E->getNameLoc(), Entity);
John McCall58cc69d2010-01-27 01:50:18 +0000766}
767
768/// Perform access-control checking on a previously-unresolved member
769/// access which has now been resolved to a member.
John McCall5b0829a2010-02-10 09:31:12 +0000770Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
John McCalla0296f72010-03-19 07:35:19 +0000771 DeclAccessPair Found) {
John McCall1064d7e2010-03-16 05:22:47 +0000772 if (!getLangOptions().AccessControl ||
John McCalla0296f72010-03-19 07:35:19 +0000773 Found.getAccess() == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000774 return AR_accessible;
John McCall58cc69d2010-01-27 01:50:18 +0000775
John McCalla0296f72010-03-19 07:35:19 +0000776 AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found);
John McCall1064d7e2010-03-16 05:22:47 +0000777 Entity.setDiag(diag::err_access) << E->getSourceRange();
778
779 return CheckAccess(*this, E->getMemberLoc(), Entity);
John McCall58cc69d2010-01-27 01:50:18 +0000780}
781
John McCall5b0829a2010-02-10 09:31:12 +0000782Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
John McCall1064d7e2010-03-16 05:22:47 +0000783 CXXDestructorDecl *Dtor,
784 const PartialDiagnostic &PDiag) {
John McCall6781b052010-02-02 08:45:54 +0000785 if (!getLangOptions().AccessControl)
John McCall5b0829a2010-02-10 09:31:12 +0000786 return AR_accessible;
John McCall6781b052010-02-02 08:45:54 +0000787
John McCall1064d7e2010-03-16 05:22:47 +0000788 // There's never a path involved when checking implicit destructor access.
John McCall6781b052010-02-02 08:45:54 +0000789 AccessSpecifier Access = Dtor->getAccess();
790 if (Access == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000791 return AR_accessible;
John McCall6781b052010-02-02 08:45:54 +0000792
John McCall1064d7e2010-03-16 05:22:47 +0000793 CXXRecordDecl *NamingClass = Dtor->getParent();
John McCalla0296f72010-03-19 07:35:19 +0000794 AccessedEntity Entity(AccessedEntity::Member, NamingClass,
795 DeclAccessPair::make(Dtor, Access));
John McCall1064d7e2010-03-16 05:22:47 +0000796 Entity.setDiag(PDiag); // TODO: avoid copy
797
798 return CheckAccess(*this, Loc, Entity);
John McCall6781b052010-02-02 08:45:54 +0000799}
800
John McCall760af172010-02-01 03:16:54 +0000801/// Checks access to a constructor.
John McCall5b0829a2010-02-10 09:31:12 +0000802Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
John McCall760af172010-02-01 03:16:54 +0000803 CXXConstructorDecl *Constructor,
804 AccessSpecifier Access) {
John McCall1064d7e2010-03-16 05:22:47 +0000805 if (!getLangOptions().AccessControl ||
806 Access == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000807 return AR_accessible;
John McCall760af172010-02-01 03:16:54 +0000808
John McCall5b0829a2010-02-10 09:31:12 +0000809 CXXRecordDecl *NamingClass = Constructor->getParent();
John McCalla0296f72010-03-19 07:35:19 +0000810 AccessedEntity Entity(AccessedEntity::Member, NamingClass,
811 DeclAccessPair::make(Constructor, Access));
John McCall1064d7e2010-03-16 05:22:47 +0000812 Entity.setDiag(diag::err_access_ctor);
813
814 return CheckAccess(*this, UseLoc, Entity);
John McCall760af172010-02-01 03:16:54 +0000815}
816
John McCallab8c2732010-03-16 06:11:48 +0000817/// Checks direct (i.e. non-inherited) access to an arbitrary class
818/// member.
819Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
820 NamedDecl *Target,
821 const PartialDiagnostic &Diag) {
822 AccessSpecifier Access = Target->getAccess();
823 if (!getLangOptions().AccessControl ||
824 Access == AS_public)
825 return AR_accessible;
826
827 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext());
John McCalla0296f72010-03-19 07:35:19 +0000828 AccessedEntity Entity(AccessedEntity::Member, NamingClass,
829 DeclAccessPair::make(Target, Access));
John McCallab8c2732010-03-16 06:11:48 +0000830 Entity.setDiag(Diag);
831 return CheckAccess(*this, UseLoc, Entity);
832}
833
834
John McCallfb6f5262010-03-18 08:19:33 +0000835/// Checks access to an overloaded operator new or delete.
836Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
837 SourceRange PlacementRange,
838 CXXRecordDecl *NamingClass,
John McCalla0296f72010-03-19 07:35:19 +0000839 DeclAccessPair Found) {
John McCallfb6f5262010-03-18 08:19:33 +0000840 if (!getLangOptions().AccessControl ||
841 !NamingClass ||
John McCalla0296f72010-03-19 07:35:19 +0000842 Found.getAccess() == AS_public)
John McCallfb6f5262010-03-18 08:19:33 +0000843 return AR_accessible;
844
John McCalla0296f72010-03-19 07:35:19 +0000845 AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found);
John McCallfb6f5262010-03-18 08:19:33 +0000846 Entity.setDiag(diag::err_access)
847 << PlacementRange;
848
849 return CheckAccess(*this, OpLoc, Entity);
850}
851
John McCall760af172010-02-01 03:16:54 +0000852/// Checks access to an overloaded member operator, including
853/// conversion operators.
John McCall5b0829a2010-02-10 09:31:12 +0000854Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
855 Expr *ObjectExpr,
John McCall1064d7e2010-03-16 05:22:47 +0000856 Expr *ArgExpr,
John McCalla0296f72010-03-19 07:35:19 +0000857 DeclAccessPair Found) {
John McCall1064d7e2010-03-16 05:22:47 +0000858 if (!getLangOptions().AccessControl ||
John McCalla0296f72010-03-19 07:35:19 +0000859 Found.getAccess() == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000860 return AR_accessible;
John McCallb3a44002010-01-28 01:42:12 +0000861
862 const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
863 assert(RT && "found member operator but object expr not of record type");
864 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
865
John McCalla0296f72010-03-19 07:35:19 +0000866 AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found);
John McCall1064d7e2010-03-16 05:22:47 +0000867 Entity.setDiag(diag::err_access)
868 << ObjectExpr->getSourceRange()
869 << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
870
871 return CheckAccess(*this, OpLoc, Entity);
John McCall5b0829a2010-02-10 09:31:12 +0000872}
John McCallb3a44002010-01-28 01:42:12 +0000873
John McCall5b0829a2010-02-10 09:31:12 +0000874/// Checks access for a hierarchy conversion.
875///
876/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
877/// or a derived-to-base conversion (false)
878/// \param ForceCheck true if this check should be performed even if access
879/// control is disabled; some things rely on this for semantics
880/// \param ForceUnprivileged true if this check should proceed as if the
881/// context had no special privileges
882/// \param ADK controls the kind of diagnostics that are used
883Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
John McCall5b0829a2010-02-10 09:31:12 +0000884 QualType Base,
885 QualType Derived,
886 const CXXBasePath &Path,
John McCall1064d7e2010-03-16 05:22:47 +0000887 unsigned DiagID,
John McCall5b0829a2010-02-10 09:31:12 +0000888 bool ForceCheck,
John McCall1064d7e2010-03-16 05:22:47 +0000889 bool ForceUnprivileged) {
John McCall5b0829a2010-02-10 09:31:12 +0000890 if (!ForceCheck && !getLangOptions().AccessControl)
891 return AR_accessible;
John McCallb3a44002010-01-28 01:42:12 +0000892
John McCall5b0829a2010-02-10 09:31:12 +0000893 if (Path.Access == AS_public)
894 return AR_accessible;
John McCallb3a44002010-01-28 01:42:12 +0000895
John McCall5b0829a2010-02-10 09:31:12 +0000896 CXXRecordDecl *BaseD, *DerivedD;
897 BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
898 DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
John McCall1064d7e2010-03-16 05:22:47 +0000899
900 AccessedEntity Entity(AccessedEntity::Base, BaseD, DerivedD, Path.Access);
901 if (DiagID)
902 Entity.setDiag(DiagID) << Derived << Base;
John McCall5b0829a2010-02-10 09:31:12 +0000903
904 if (ForceUnprivileged)
John McCall1064d7e2010-03-16 05:22:47 +0000905 return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity);
906 return CheckAccess(*this, AccessLoc, Entity);
John McCallb3a44002010-01-28 01:42:12 +0000907}
908
John McCall553c0792010-01-23 00:46:32 +0000909/// Checks access to all the declarations in the given result set.
John McCall5b0829a2010-02-10 09:31:12 +0000910void Sema::CheckLookupAccess(const LookupResult &R) {
911 assert(getLangOptions().AccessControl
912 && "performing access check without access control");
913 assert(R.getNamingClass() && "performing access check without naming class");
914
John McCall1064d7e2010-03-16 05:22:47 +0000915 for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
916 if (I.getAccess() != AS_public) {
917 AccessedEntity Entity(AccessedEntity::Member,
John McCalla0296f72010-03-19 07:35:19 +0000918 R.getNamingClass(),
919 I.getPair());
John McCall1064d7e2010-03-16 05:22:47 +0000920 Entity.setDiag(diag::err_access);
921
922 CheckAccess(*this, R.getNameLoc(), Entity);
923 }
924 }
John McCall553c0792010-01-23 00:46:32 +0000925}