blob: a92989696e3101982144faa0470e9fcee536997f [file] [log] [blame]
Anders Carlsson29f006b2009-03-27 05:05:05 +00001//===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===//
Anders Carlsson60d6b0d2009-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 Carlssonc60e8882009-03-27 04:54:36 +000013
14#include "Sema.h"
John McCall92f88312010-01-23 00:46:32 +000015#include "Lookup.h"
Anders Carlssonc4f1e872009-03-27 06:03:27 +000016#include "clang/AST/ASTContext.h"
Douglas Gregora8f32e02009-10-06 17:59:45 +000017#include "clang/AST/CXXInheritance.h"
18#include "clang/AST/DeclCXX.h"
John McCalld60e22e2010-03-12 01:19:31 +000019#include "clang/AST/DeclFriend.h"
John McCall0c01d182010-03-24 05:22:00 +000020#include "clang/AST/DependentDiagnostic.h"
John McCallc373d482010-01-27 01:50:18 +000021#include "clang/AST/ExprCXX.h"
22
Anders Carlssonc60e8882009-03-27 04:54:36 +000023using namespace clang;
24
Anders Carlsson29f006b2009-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 Stump1eb44332009-09-09 15:08:12 +000028bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
Anders Carlssonc60e8882009-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 Stump1eb44332009-09-09 15:08:12 +000036
Anders Carlssonc60e8882009-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 Stump1eb44332009-09-09 15:08:12 +000040 Diag(MemberDecl->getLocation(),
41 diag::err_class_redeclared_with_different_access)
Anders Carlssonc60e8882009-03-27 04:54:36 +000042 << MemberDecl << LexicalAS;
43 Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)
44 << PrevMemberDecl << PrevMemberDecl->getAccess();
John McCall44e067b2009-12-23 00:37:40 +000045
46 MemberDecl->setAccess(LexicalAS);
Anders Carlssonc60e8882009-03-27 04:54:36 +000047 return true;
48 }
Mike Stump1eb44332009-09-09 15:08:12 +000049
Anders Carlssonc60e8882009-03-27 04:54:36 +000050 MemberDecl->setAccess(PrevMemberDecl->getAccess());
51 return false;
52}
Anders Carlsson29f006b2009-03-27 05:05:05 +000053
John McCall6b2accb2010-02-10 09:31:12 +000054namespace {
55struct EffectiveContext {
John McCall7ad650f2010-03-24 07:46:06 +000056 EffectiveContext() : Inner(0), Function(0), Dependent(false) {}
Anders Carlssonc4f1e872009-03-27 06:03:27 +000057
John McCall7ad650f2010-03-24 07:46:06 +000058 explicit EffectiveContext(DeclContext *DC)
59 : Inner(DC),
60 Dependent(DC->isDependentContext()) {
John McCall0c01d182010-03-24 05:22:00 +000061
John McCallc1b621d2010-03-24 09:04:37 +000062 if (isa<EnumDecl>(DC))
63 DC = cast<EnumDecl>(DC)->getDeclContext();
64
John McCall6b2accb2010-02-10 09:31:12 +000065 if (isa<FunctionDecl>(DC)) {
John McCalld60e22e2010-03-12 01:19:31 +000066 Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
John McCall6b2accb2010-02-10 09:31:12 +000067 DC = Function->getDeclContext();
68 } else
69 Function = 0;
John McCall88b6c712010-03-17 04:58:56 +000070
71 // C++ [class.access.nest]p1:
72 // A nested class is a member and as such has the same access
73 // rights as any other member.
74 // C++ [class.access]p2:
75 // A member of a class can also access all the names to which
76 // the class has access.
77 // This implies that the privileges of nesting are transitive.
78 while (isa<CXXRecordDecl>(DC)) {
79 CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
80 Records.push_back(Record);
81 DC = Record->getDeclContext();
82 }
Anders Carlssonc4f1e872009-03-27 06:03:27 +000083 }
Sebastian Redl726212f2009-07-18 14:32:15 +000084
John McCall0c01d182010-03-24 05:22:00 +000085 bool isDependent() const { return Dependent; }
86
John McCall88b6c712010-03-17 04:58:56 +000087 bool includesClass(const CXXRecordDecl *R) const {
88 R = R->getCanonicalDecl();
89 return std::find(Records.begin(), Records.end(), R)
90 != Records.end();
John McCall6b2accb2010-02-10 09:31:12 +000091 }
92
John McCall7ad650f2010-03-24 07:46:06 +000093 /// Retrieves the innermost "useful" context. Can be null if we're
94 /// doing access-control without privileges.
95 DeclContext *getInnerContext() const {
96 return Inner;
John McCall0c01d182010-03-24 05:22:00 +000097 }
98
99 typedef llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;
100
John McCall7ad650f2010-03-24 07:46:06 +0000101 DeclContext *Inner;
John McCall88b6c712010-03-17 04:58:56 +0000102 llvm::SmallVector<CXXRecordDecl*, 4> Records;
John McCall6b2accb2010-02-10 09:31:12 +0000103 FunctionDecl *Function;
John McCall0c01d182010-03-24 05:22:00 +0000104 bool Dependent;
John McCall6b2accb2010-02-10 09:31:12 +0000105};
Anders Carlsson29f006b2009-03-27 05:05:05 +0000106}
John McCall92f88312010-01-23 00:46:32 +0000107
John McCall6b2accb2010-02-10 09:31:12 +0000108static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
John McCallc1b621d2010-03-24 09:04:37 +0000109 DeclContext *DC = D->getDeclContext();
110
111 // This can only happen at top: enum decls only "publish" their
112 // immediate members.
113 if (isa<EnumDecl>(DC))
114 DC = cast<EnumDecl>(DC)->getDeclContext();
115
116 CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC);
John McCall6b2accb2010-02-10 09:31:12 +0000117 while (DeclaringClass->isAnonymousStructOrUnion())
118 DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
119 return DeclaringClass;
120}
121
John McCall0c01d182010-03-24 05:22:00 +0000122static bool MightInstantiateTo(Sema &S, DeclContext *Context,
123 DeclContext *Friend) {
124 if (Friend == Context)
125 return true;
126
127 assert(!Friend->isDependentContext() &&
128 "can't handle friends with dependent contexts here");
129
130 if (!Context->isDependentContext())
131 return false;
132
133 if (Friend->isFileContext())
134 return false;
135
136 // TODO: this is very conservative
137 return true;
138}
139
140// Asks whether the type in 'context' can ever instantiate to the type
141// in 'friend'.
142static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) {
143 if (Friend == Context)
144 return true;
145
146 if (!Friend->isDependentType() && !Context->isDependentType())
147 return false;
148
149 // TODO: this is very conservative.
150 return true;
151}
152
153static bool MightInstantiateTo(Sema &S,
154 FunctionDecl *Context,
155 FunctionDecl *Friend) {
156 if (Context->getDeclName() != Friend->getDeclName())
157 return false;
158
159 if (!MightInstantiateTo(S,
160 Context->getDeclContext(),
161 Friend->getDeclContext()))
162 return false;
163
164 CanQual<FunctionProtoType> FriendTy
165 = S.Context.getCanonicalType(Friend->getType())
166 ->getAs<FunctionProtoType>();
167 CanQual<FunctionProtoType> ContextTy
168 = S.Context.getCanonicalType(Context->getType())
169 ->getAs<FunctionProtoType>();
170
171 // There isn't any way that I know of to add qualifiers
172 // during instantiation.
173 if (FriendTy.getQualifiers() != ContextTy.getQualifiers())
174 return false;
175
176 if (FriendTy->getNumArgs() != ContextTy->getNumArgs())
177 return false;
178
179 if (!MightInstantiateTo(S,
180 ContextTy->getResultType(),
181 FriendTy->getResultType()))
182 return false;
183
184 for (unsigned I = 0, E = FriendTy->getNumArgs(); I != E; ++I)
185 if (!MightInstantiateTo(S,
186 ContextTy->getArgType(I),
187 FriendTy->getArgType(I)))
188 return false;
189
190 return true;
191}
192
193static bool MightInstantiateTo(Sema &S,
194 FunctionTemplateDecl *Context,
195 FunctionTemplateDecl *Friend) {
196 return MightInstantiateTo(S,
197 Context->getTemplatedDecl(),
198 Friend->getTemplatedDecl());
199}
200
John McCalla742db02010-03-17 20:01:29 +0000201static Sema::AccessResult MatchesFriend(Sema &S,
202 const EffectiveContext &EC,
203 const CXXRecordDecl *Friend) {
John McCalla742db02010-03-17 20:01:29 +0000204 if (EC.includesClass(Friend))
205 return Sema::AR_accessible;
206
John McCall0c01d182010-03-24 05:22:00 +0000207 if (EC.isDependent()) {
208 CanQualType FriendTy
209 = S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend));
210
211 for (EffectiveContext::record_iterator
212 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
213 CanQualType ContextTy
214 = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I));
215 if (MightInstantiateTo(S, ContextTy, FriendTy))
216 return Sema::AR_dependent;
217 }
218 }
219
John McCalla742db02010-03-17 20:01:29 +0000220 return Sema::AR_inaccessible;
221}
222
223static Sema::AccessResult MatchesFriend(Sema &S,
224 const EffectiveContext &EC,
John McCall0c01d182010-03-24 05:22:00 +0000225 CanQualType Friend) {
226 if (const RecordType *RT = Friend->getAs<RecordType>())
227 return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));
John McCalla742db02010-03-17 20:01:29 +0000228
John McCall0c01d182010-03-24 05:22:00 +0000229 // TODO: we can do better than this
230 if (Friend->isDependentType())
231 return Sema::AR_dependent;
John McCalla742db02010-03-17 20:01:29 +0000232
John McCall0c01d182010-03-24 05:22:00 +0000233 return Sema::AR_inaccessible;
234}
235
236/// Determines whether the given friend class template matches
237/// anything in the effective context.
238static Sema::AccessResult MatchesFriend(Sema &S,
239 const EffectiveContext &EC,
240 ClassTemplateDecl *Friend) {
241 Sema::AccessResult OnFailure = Sema::AR_inaccessible;
242
John McCall93ba8572010-03-25 06:39:04 +0000243 // Check whether the friend is the template of a class in the
244 // context chain.
John McCall0c01d182010-03-24 05:22:00 +0000245 for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
246 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
247 CXXRecordDecl *Record = *I;
248
John McCall93ba8572010-03-25 06:39:04 +0000249 // Figure out whether the current class has a template:
John McCall0c01d182010-03-24 05:22:00 +0000250 ClassTemplateDecl *CTD;
251
252 // A specialization of the template...
253 if (isa<ClassTemplateSpecializationDecl>(Record)) {
254 CTD = cast<ClassTemplateSpecializationDecl>(Record)
255 ->getSpecializedTemplate();
256
257 // ... or the template pattern itself.
258 } else {
259 CTD = Record->getDescribedClassTemplate();
260 if (!CTD) continue;
261 }
262
263 // It's a match.
264 if (Friend == CTD->getCanonicalDecl())
265 return Sema::AR_accessible;
266
John McCall93ba8572010-03-25 06:39:04 +0000267 // If the context isn't dependent, it can't be a dependent match.
268 if (!EC.isDependent())
269 continue;
270
John McCall0c01d182010-03-24 05:22:00 +0000271 // If the template names don't match, it can't be a dependent
272 // match. This isn't true in C++0x because of template aliases.
273 if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName())
274 continue;
275
276 // If the class's context can't instantiate to the friend's
277 // context, it can't be a dependent match.
278 if (!MightInstantiateTo(S, CTD->getDeclContext(),
279 Friend->getDeclContext()))
280 continue;
281
282 // Otherwise, it's a dependent match.
283 OnFailure = Sema::AR_dependent;
John McCalla742db02010-03-17 20:01:29 +0000284 }
285
John McCall0c01d182010-03-24 05:22:00 +0000286 return OnFailure;
287}
288
289/// Determines whether the given friend function matches anything in
290/// the effective context.
291static Sema::AccessResult MatchesFriend(Sema &S,
292 const EffectiveContext &EC,
293 FunctionDecl *Friend) {
294 if (!EC.Function)
295 return Sema::AR_inaccessible;
296
297 if (Friend == EC.Function)
298 return Sema::AR_accessible;
299
300 if (EC.isDependent() && MightInstantiateTo(S, EC.Function, Friend))
301 return Sema::AR_dependent;
302
303 return Sema::AR_inaccessible;
304}
305
306/// Determines whether the given friend function template matches
307/// anything in the effective context.
308static Sema::AccessResult MatchesFriend(Sema &S,
309 const EffectiveContext &EC,
310 FunctionTemplateDecl *Friend) {
311 if (!EC.Function) return Sema::AR_inaccessible;
312
313 FunctionTemplateDecl *FTD = EC.Function->getPrimaryTemplate();
314 if (!FTD)
315 FTD = EC.Function->getDescribedFunctionTemplate();
316 if (!FTD)
317 return Sema::AR_inaccessible;
318
319 if (Friend == FTD->getCanonicalDecl())
320 return Sema::AR_accessible;
321
322 if (MightInstantiateTo(S, FTD, Friend))
323 return Sema::AR_dependent;
324
325 return Sema::AR_inaccessible;
326}
327
328/// Determines whether the given friend declaration matches anything
329/// in the effective context.
330static Sema::AccessResult MatchesFriend(Sema &S,
331 const EffectiveContext &EC,
332 FriendDecl *FriendD) {
John McCall32f2fb52010-03-25 18:04:51 +0000333 if (TypeSourceInfo *T = FriendD->getFriendType())
334 return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified());
John McCall0c01d182010-03-24 05:22:00 +0000335
336 NamedDecl *Friend
337 = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl());
John McCalla742db02010-03-17 20:01:29 +0000338
339 // FIXME: declarations with dependent or templated scope.
340
John McCall0c01d182010-03-24 05:22:00 +0000341 if (isa<ClassTemplateDecl>(Friend))
342 return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend));
John McCalla742db02010-03-17 20:01:29 +0000343
John McCall0c01d182010-03-24 05:22:00 +0000344 if (isa<FunctionTemplateDecl>(Friend))
345 return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend));
John McCalla742db02010-03-17 20:01:29 +0000346
John McCall0c01d182010-03-24 05:22:00 +0000347 if (isa<CXXRecordDecl>(Friend))
348 return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend));
John McCalla742db02010-03-17 20:01:29 +0000349
John McCall0c01d182010-03-24 05:22:00 +0000350 assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind");
351 return MatchesFriend(S, EC, cast<FunctionDecl>(Friend));
John McCalla742db02010-03-17 20:01:29 +0000352}
353
John McCall6b2accb2010-02-10 09:31:12 +0000354static Sema::AccessResult GetFriendKind(Sema &S,
355 const EffectiveContext &EC,
356 const CXXRecordDecl *Class) {
John McCalld60e22e2010-03-12 01:19:31 +0000357 // A class always has access to its own members.
John McCall88b6c712010-03-17 04:58:56 +0000358 if (EC.includesClass(Class))
John McCall6b2accb2010-02-10 09:31:12 +0000359 return Sema::AR_accessible;
360
John McCall88b6c712010-03-17 04:58:56 +0000361 Sema::AccessResult OnFailure = Sema::AR_inaccessible;
362
John McCalld60e22e2010-03-12 01:19:31 +0000363 // Okay, check friends.
364 for (CXXRecordDecl::friend_iterator I = Class->friend_begin(),
365 E = Class->friend_end(); I != E; ++I) {
366 FriendDecl *Friend = *I;
367
John McCalla742db02010-03-17 20:01:29 +0000368 switch (MatchesFriend(S, EC, Friend)) {
369 case Sema::AR_accessible:
370 return Sema::AR_accessible;
John McCalld60e22e2010-03-12 01:19:31 +0000371
John McCalla742db02010-03-17 20:01:29 +0000372 case Sema::AR_inaccessible:
373 break;
John McCall88b6c712010-03-17 04:58:56 +0000374
John McCalla742db02010-03-17 20:01:29 +0000375 case Sema::AR_dependent:
376 OnFailure = Sema::AR_dependent;
377 break;
378
379 case Sema::AR_delayed:
380 llvm_unreachable("cannot get delayed answer from MatchesFriend");
John McCalld60e22e2010-03-12 01:19:31 +0000381 }
John McCalld60e22e2010-03-12 01:19:31 +0000382 }
383
384 // That's it, give up.
John McCall88b6c712010-03-17 04:58:56 +0000385 return OnFailure;
John McCall6b2accb2010-02-10 09:31:12 +0000386}
387
388/// Finds the best path from the naming class to the declaring class,
389/// taking friend declarations into account.
390///
John McCall7aceaf82010-03-18 23:49:19 +0000391/// \param FinalAccess the access of the "final step", or AS_none if
392/// there is no final step.
John McCall6b2accb2010-02-10 09:31:12 +0000393/// \return null if friendship is dependent
394static CXXBasePath *FindBestPath(Sema &S,
395 const EffectiveContext &EC,
396 CXXRecordDecl *Derived,
397 CXXRecordDecl *Base,
John McCall7aceaf82010-03-18 23:49:19 +0000398 AccessSpecifier FinalAccess,
John McCall6b2accb2010-02-10 09:31:12 +0000399 CXXBasePaths &Paths) {
400 // Derive the paths to the desired base.
401 bool isDerived = Derived->isDerivedFrom(Base, Paths);
402 assert(isDerived && "derived class not actually derived from base");
403 (void) isDerived;
404
405 CXXBasePath *BestPath = 0;
406
John McCall7aceaf82010-03-18 23:49:19 +0000407 assert(FinalAccess != AS_none && "forbidden access after declaring class");
408
John McCall0c01d182010-03-24 05:22:00 +0000409 bool AnyDependent = false;
410
John McCall6b2accb2010-02-10 09:31:12 +0000411 // Derive the friend-modified access along each path.
412 for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
413 PI != PE; ++PI) {
414
415 // Walk through the path backwards.
John McCall7aceaf82010-03-18 23:49:19 +0000416 AccessSpecifier PathAccess = FinalAccess;
John McCall6b2accb2010-02-10 09:31:12 +0000417 CXXBasePath::iterator I = PI->end(), E = PI->begin();
418 while (I != E) {
419 --I;
420
John McCall7aceaf82010-03-18 23:49:19 +0000421 assert(PathAccess != AS_none);
422
423 // If the declaration is a private member of a base class, there
424 // is no level of friendship in derived classes that can make it
425 // accessible.
426 if (PathAccess == AS_private) {
427 PathAccess = AS_none;
428 break;
429 }
430
John McCall6b2accb2010-02-10 09:31:12 +0000431 AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
John McCalle06c1a12010-03-25 21:39:55 +0000432 if (BaseAccess != AS_public || PathAccess != AS_public) {
John McCall6b2accb2010-02-10 09:31:12 +0000433 switch (GetFriendKind(S, EC, I->Class)) {
John McCall7aceaf82010-03-18 23:49:19 +0000434 case Sema::AR_inaccessible:
435 PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess);
436 break;
437 case Sema::AR_accessible:
438 PathAccess = AS_public;
439 break;
440 case Sema::AR_dependent:
John McCall0c01d182010-03-24 05:22:00 +0000441 AnyDependent = true;
442 goto Next;
John McCall6b2accb2010-02-10 09:31:12 +0000443 case Sema::AR_delayed:
444 llvm_unreachable("friend resolution is never delayed"); break;
445 }
446 }
John McCall6b2accb2010-02-10 09:31:12 +0000447 }
448
449 // Note that we modify the path's Access field to the
450 // friend-modified access.
451 if (BestPath == 0 || PathAccess < BestPath->Access) {
452 BestPath = &*PI;
453 BestPath->Access = PathAccess;
John McCall0c01d182010-03-24 05:22:00 +0000454
455 // Short-circuit if we found a public path.
456 if (BestPath->Access == AS_public)
457 return BestPath;
John McCall6b2accb2010-02-10 09:31:12 +0000458 }
John McCall0c01d182010-03-24 05:22:00 +0000459
460 Next: ;
John McCall6b2accb2010-02-10 09:31:12 +0000461 }
462
John McCall0c01d182010-03-24 05:22:00 +0000463 assert((!BestPath || BestPath->Access != AS_public) &&
464 "fell out of loop with public path");
465
466 // We didn't find a public path, but at least one path was subject
467 // to dependent friendship, so delay the check.
468 if (AnyDependent)
469 return 0;
470
John McCall6b2accb2010-02-10 09:31:12 +0000471 return BestPath;
472}
473
474/// Diagnose the path which caused the given declaration or base class
475/// to become inaccessible.
476static void DiagnoseAccessPath(Sema &S,
477 const EffectiveContext &EC,
478 CXXRecordDecl *NamingClass,
479 CXXRecordDecl *DeclaringClass,
480 NamedDecl *D, AccessSpecifier Access) {
John McCall92f88312010-01-23 00:46:32 +0000481 // Easy case: the decl's natural access determined its path access.
John McCall6b2accb2010-02-10 09:31:12 +0000482 // We have to check against AS_private here in case Access is AS_none,
483 // indicating a non-public member of a private base class.
484 //
485 // DependentFriend should be impossible here.
486 if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
487 switch (GetFriendKind(S, EC, DeclaringClass)) {
488 case Sema::AR_inaccessible: {
489 S.Diag(D->getLocation(), diag::note_access_natural)
490 << (unsigned) (Access == AS_protected)
491 << /*FIXME: not implicitly*/ 0;
492 return;
493 }
494
495 case Sema::AR_accessible: break;
496
497 case Sema::AR_dependent:
498 case Sema::AR_delayed:
499 llvm_unreachable("dependent/delayed not allowed");
500 return;
501 }
502 }
503
504 CXXBasePaths Paths;
John McCall7aceaf82010-03-18 23:49:19 +0000505 CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass,
506 AS_public, Paths);
John McCall6b2accb2010-02-10 09:31:12 +0000507
508 CXXBasePath::iterator I = Path.end(), E = Path.begin();
509 while (I != E) {
510 --I;
511
512 const CXXBaseSpecifier *BS = I->Base;
513 AccessSpecifier BaseAccess = BS->getAccessSpecifier();
514
515 // If this is public inheritance, or the derived class is a friend,
516 // skip this step.
517 if (BaseAccess == AS_public)
518 continue;
519
520 switch (GetFriendKind(S, EC, I->Class)) {
521 case Sema::AR_accessible: continue;
522 case Sema::AR_inaccessible: break;
523
524 case Sema::AR_dependent:
525 case Sema::AR_delayed:
526 llvm_unreachable("dependent friendship, should not be diagnosing");
527 }
528
529 // Check whether this base specifier is the tighest point
530 // constraining access. We have to check against AS_private for
531 // the same reasons as above.
532 if (BaseAccess == AS_private || BaseAccess >= Access) {
533
534 // We're constrained by inheritance, but we want to say
535 // "declared private here" if we're diagnosing a hierarchy
536 // conversion and this is the final step.
537 unsigned diagnostic;
538 if (D) diagnostic = diag::note_access_constrained_by_path;
539 else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural;
540 else diagnostic = diag::note_access_constrained_by_path;
541
542 S.Diag(BS->getSourceRange().getBegin(), diagnostic)
543 << BS->getSourceRange()
544 << (BaseAccess == AS_protected)
545 << (BS->getAccessSpecifierAsWritten() == AS_none);
546 return;
547 }
548 }
549
550 llvm_unreachable("access not apparently constrained by path");
551}
552
553/// Diagnose an inaccessible class member.
554static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc,
555 const EffectiveContext &EC,
556 CXXRecordDecl *NamingClass,
557 AccessSpecifier Access,
558 const Sema::AccessedEntity &Entity) {
559 NamedDecl *D = Entity.getTargetDecl();
560 CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
561
John McCall58e6f342010-03-16 05:22:47 +0000562 S.Diag(Loc, Entity.getDiag())
563 << (Access == AS_protected)
564 << D->getDeclName()
565 << S.Context.getTypeDeclType(NamingClass)
566 << S.Context.getTypeDeclType(DeclaringClass);
John McCall6b2accb2010-02-10 09:31:12 +0000567 DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
568}
569
570/// Diagnose an inaccessible hierarchy conversion.
571static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc,
572 const EffectiveContext &EC,
573 AccessSpecifier Access,
John McCall58e6f342010-03-16 05:22:47 +0000574 const Sema::AccessedEntity &Entity) {
575 S.Diag(Loc, Entity.getDiag())
576 << (Access == AS_protected)
577 << DeclarationName()
578 << S.Context.getTypeDeclType(Entity.getDerivedClass())
579 << S.Context.getTypeDeclType(Entity.getBaseClass());
John McCall6b2accb2010-02-10 09:31:12 +0000580 DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
581 Entity.getBaseClass(), 0, Access);
582}
583
John McCall58e6f342010-03-16 05:22:47 +0000584static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
John McCall6b2accb2010-02-10 09:31:12 +0000585 const EffectiveContext &EC,
586 CXXRecordDecl *NamingClass,
587 AccessSpecifier Access,
John McCall58e6f342010-03-16 05:22:47 +0000588 const Sema::AccessedEntity &Entity) {
John McCall6b2accb2010-02-10 09:31:12 +0000589 if (Entity.isMemberAccess())
590 DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
591 else
John McCall58e6f342010-03-16 05:22:47 +0000592 DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity);
John McCall6b2accb2010-02-10 09:31:12 +0000593}
594
595
596/// Try to elevate access using friend declarations. This is
597/// potentially quite expensive.
John McCall0c01d182010-03-24 05:22:00 +0000598///
599/// \return true if elevation was dependent
600static bool TryElevateAccess(Sema &S,
John McCall6b2accb2010-02-10 09:31:12 +0000601 const EffectiveContext &EC,
602 const Sema::AccessedEntity &Entity,
603 AccessSpecifier &Access) {
604 CXXRecordDecl *DeclaringClass;
605 if (Entity.isMemberAccess()) {
606 DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
607 } else {
608 DeclaringClass = Entity.getBaseClass();
609 }
610 CXXRecordDecl *NamingClass = Entity.getNamingClass();
611
612 // Adjust the declaration of the referred entity.
John McCall7aceaf82010-03-18 23:49:19 +0000613 AccessSpecifier DeclAccess = AS_public;
John McCall6b2accb2010-02-10 09:31:12 +0000614 if (Entity.isMemberAccess()) {
615 NamedDecl *Target = Entity.getTargetDecl();
616
617 DeclAccess = Target->getAccess();
618 if (DeclAccess != AS_public) {
619 switch (GetFriendKind(S, EC, DeclaringClass)) {
620 case Sema::AR_accessible: DeclAccess = AS_public; break;
621 case Sema::AR_inaccessible: break;
John McCall0c01d182010-03-24 05:22:00 +0000622 case Sema::AR_dependent: return true;
John McCall6b2accb2010-02-10 09:31:12 +0000623 case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
624 }
625 }
626
627 if (DeclaringClass == NamingClass) {
628 Access = DeclAccess;
John McCall0c01d182010-03-24 05:22:00 +0000629 return false;
John McCall6b2accb2010-02-10 09:31:12 +0000630 }
631 }
632
633 assert(DeclaringClass != NamingClass);
634
635 // Append the declaration's access if applicable.
636 CXXBasePaths Paths;
637 CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(),
John McCall7aceaf82010-03-18 23:49:19 +0000638 DeclaringClass, DeclAccess, Paths);
John McCall0c01d182010-03-24 05:22:00 +0000639 if (!Path)
640 return true;
John McCall92f88312010-01-23 00:46:32 +0000641
John McCall7aceaf82010-03-18 23:49:19 +0000642 // Grab the access along the best path (note that this includes the
643 // final-step access).
John McCall6b2accb2010-02-10 09:31:12 +0000644 AccessSpecifier NewAccess = Path->Access;
John McCall6b2accb2010-02-10 09:31:12 +0000645 assert(NewAccess <= Access && "access along best path worse than direct?");
646 Access = NewAccess;
John McCall0c01d182010-03-24 05:22:00 +0000647 return false;
648}
649
650static void DelayAccess(Sema &S,
651 const EffectiveContext &EC,
652 SourceLocation Loc,
653 const Sema::AccessedEntity &Entity) {
654 assert(EC.isDependent() && "delaying non-dependent access");
John McCall7ad650f2010-03-24 07:46:06 +0000655 DeclContext *DC = EC.getInnerContext();
John McCall0c01d182010-03-24 05:22:00 +0000656 assert(DC->isDependentContext() && "delaying non-dependent access");
657 DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access,
658 Loc,
659 Entity.isMemberAccess(),
660 Entity.getAccess(),
661 Entity.getTargetDecl(),
662 Entity.getNamingClass(),
663 Entity.getDiag());
John McCall92f88312010-01-23 00:46:32 +0000664}
665
John McCall6b2accb2010-02-10 09:31:12 +0000666/// Checks access to an entity from the given effective context.
667static Sema::AccessResult CheckEffectiveAccess(Sema &S,
668 const EffectiveContext &EC,
669 SourceLocation Loc,
John McCall58e6f342010-03-16 05:22:47 +0000670 Sema::AccessedEntity const &Entity) {
John McCall6b2accb2010-02-10 09:31:12 +0000671 AccessSpecifier Access = Entity.getAccess();
John McCall88b6c712010-03-17 04:58:56 +0000672 assert(Access != AS_public && "called for public access!");
John McCall92f88312010-01-23 00:46:32 +0000673
John McCall88b6c712010-03-17 04:58:56 +0000674 // Find a non-anonymous naming class. For records with access,
675 // there should always be one of these.
John McCall6b2accb2010-02-10 09:31:12 +0000676 CXXRecordDecl *NamingClass = Entity.getNamingClass();
John McCall92f88312010-01-23 00:46:32 +0000677 while (NamingClass->isAnonymousStructOrUnion())
John McCall58e6f342010-03-16 05:22:47 +0000678 NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
John McCall92f88312010-01-23 00:46:32 +0000679
John McCall88b6c712010-03-17 04:58:56 +0000680 // White-list accesses from classes with privileges equivalent to the
681 // naming class --- but only if the access path isn't forbidden
682 // (i.e. an access of a private member from a subclass).
683 if (Access != AS_none && EC.includesClass(NamingClass))
John McCall6b2accb2010-02-10 09:31:12 +0000684 return Sema::AR_accessible;
John McCall88b6c712010-03-17 04:58:56 +0000685
686 // Try to elevate access.
John McCall88b6c712010-03-17 04:58:56 +0000687 // TODO: on some code, it might be better to do the protected check
688 // without trying to elevate first.
John McCall0c01d182010-03-24 05:22:00 +0000689 if (TryElevateAccess(S, EC, Entity, Access)) {
690 DelayAccess(S, EC, Loc, Entity);
691 return Sema::AR_dependent;
692 }
693
John McCall88b6c712010-03-17 04:58:56 +0000694 if (Access == AS_public) return Sema::AR_accessible;
John McCall92f88312010-01-23 00:46:32 +0000695
696 // Protected access.
697 if (Access == AS_protected) {
698 // FIXME: implement [class.protected]p1
John McCall88b6c712010-03-17 04:58:56 +0000699 for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
700 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I)
701 if ((*I)->isDerivedFrom(NamingClass))
702 return Sema::AR_accessible;
John McCall92f88312010-01-23 00:46:32 +0000703
John McCall88b6c712010-03-17 04:58:56 +0000704 // FIXME: delay if we can't decide class derivation yet.
John McCall92f88312010-01-23 00:46:32 +0000705 }
706
John McCall6b2accb2010-02-10 09:31:12 +0000707 // Okay, that's it, reject it.
John McCall58e6f342010-03-16 05:22:47 +0000708 if (!Entity.isQuiet())
709 DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
John McCall6b2accb2010-02-10 09:31:12 +0000710 return Sema::AR_inaccessible;
711}
John McCall92f88312010-01-23 00:46:32 +0000712
John McCall6b2accb2010-02-10 09:31:12 +0000713static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
John McCall58e6f342010-03-16 05:22:47 +0000714 const Sema::AccessedEntity &Entity) {
John McCall6b2accb2010-02-10 09:31:12 +0000715 // If the access path is public, it's accessible everywhere.
716 if (Entity.getAccess() == AS_public)
717 return Sema::AR_accessible;
John McCall92f88312010-01-23 00:46:32 +0000718
John McCall6b2accb2010-02-10 09:31:12 +0000719 // If we're currently parsing a top-level declaration, delay
720 // diagnostics. This is the only case where parsing a declaration
721 // can actually change our effective context for the purposes of
722 // access control.
723 if (S.CurContext->isFileContext() && S.ParsingDeclDepth) {
John McCall6b2accb2010-02-10 09:31:12 +0000724 S.DelayedDiagnostics.push_back(
725 Sema::DelayedDiagnostic::makeAccess(Loc, Entity));
726 return Sema::AR_delayed;
John McCall92f88312010-01-23 00:46:32 +0000727 }
728
John McCall6b2accb2010-02-10 09:31:12 +0000729 return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
John McCall58e6f342010-03-16 05:22:47 +0000730 Loc, Entity);
John McCall92f88312010-01-23 00:46:32 +0000731}
732
John McCall2f514482010-01-27 03:50:35 +0000733void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
John McCall2f514482010-01-27 03:50:35 +0000734 // Pretend we did this from the context of the newly-parsed
735 // declaration.
John McCall6b2accb2010-02-10 09:31:12 +0000736 EffectiveContext EC(Ctx->getDeclContext());
John McCall2f514482010-01-27 03:50:35 +0000737
John McCall58e6f342010-03-16 05:22:47 +0000738 if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData()))
John McCall2f514482010-01-27 03:50:35 +0000739 DD.Triggered = true;
740}
741
John McCall0c01d182010-03-24 05:22:00 +0000742void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,
743 const MultiLevelTemplateArgumentList &TemplateArgs) {
744 SourceLocation Loc = DD.getAccessLoc();
745 AccessSpecifier Access = DD.getAccess();
746
747 Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(),
748 TemplateArgs);
749 if (!NamingD) return;
750 Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(),
751 TemplateArgs);
752 if (!TargetD) return;
753
754 if (DD.isAccessToMember()) {
755 AccessedEntity Entity(AccessedEntity::Member,
756 cast<CXXRecordDecl>(NamingD),
757 Access,
758 cast<NamedDecl>(TargetD));
759 Entity.setDiag(DD.getDiagnostic());
760 CheckAccess(*this, Loc, Entity);
761 } else {
762 AccessedEntity Entity(AccessedEntity::Base,
763 cast<CXXRecordDecl>(TargetD),
764 cast<CXXRecordDecl>(NamingD),
765 Access);
766 Entity.setDiag(DD.getDiagnostic());
767 CheckAccess(*this, Loc, Entity);
768 }
769}
770
John McCall6b2accb2010-02-10 09:31:12 +0000771Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
John McCall9aa472c2010-03-19 07:35:19 +0000772 DeclAccessPair Found) {
John McCall58e6f342010-03-16 05:22:47 +0000773 if (!getLangOptions().AccessControl ||
774 !E->getNamingClass() ||
John McCall9aa472c2010-03-19 07:35:19 +0000775 Found.getAccess() == AS_public)
John McCall6b2accb2010-02-10 09:31:12 +0000776 return AR_accessible;
John McCallc373d482010-01-27 01:50:18 +0000777
John McCall9aa472c2010-03-19 07:35:19 +0000778 AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found);
John McCall58e6f342010-03-16 05:22:47 +0000779 Entity.setDiag(diag::err_access) << E->getSourceRange();
780
781 return CheckAccess(*this, E->getNameLoc(), Entity);
John McCallc373d482010-01-27 01:50:18 +0000782}
783
784/// Perform access-control checking on a previously-unresolved member
785/// access which has now been resolved to a member.
John McCall6b2accb2010-02-10 09:31:12 +0000786Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
John McCall9aa472c2010-03-19 07:35:19 +0000787 DeclAccessPair Found) {
John McCall58e6f342010-03-16 05:22:47 +0000788 if (!getLangOptions().AccessControl ||
John McCall9aa472c2010-03-19 07:35:19 +0000789 Found.getAccess() == AS_public)
John McCall6b2accb2010-02-10 09:31:12 +0000790 return AR_accessible;
John McCallc373d482010-01-27 01:50:18 +0000791
John McCall9aa472c2010-03-19 07:35:19 +0000792 AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found);
John McCall58e6f342010-03-16 05:22:47 +0000793 Entity.setDiag(diag::err_access) << E->getSourceRange();
794
795 return CheckAccess(*this, E->getMemberLoc(), Entity);
John McCallc373d482010-01-27 01:50:18 +0000796}
797
John McCall6b2accb2010-02-10 09:31:12 +0000798Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
John McCall58e6f342010-03-16 05:22:47 +0000799 CXXDestructorDecl *Dtor,
800 const PartialDiagnostic &PDiag) {
John McCall4f9506a2010-02-02 08:45:54 +0000801 if (!getLangOptions().AccessControl)
John McCall6b2accb2010-02-10 09:31:12 +0000802 return AR_accessible;
John McCall4f9506a2010-02-02 08:45:54 +0000803
John McCall58e6f342010-03-16 05:22:47 +0000804 // There's never a path involved when checking implicit destructor access.
John McCall4f9506a2010-02-02 08:45:54 +0000805 AccessSpecifier Access = Dtor->getAccess();
806 if (Access == AS_public)
John McCall6b2accb2010-02-10 09:31:12 +0000807 return AR_accessible;
John McCall4f9506a2010-02-02 08:45:54 +0000808
John McCall58e6f342010-03-16 05:22:47 +0000809 CXXRecordDecl *NamingClass = Dtor->getParent();
John McCall9aa472c2010-03-19 07:35:19 +0000810 AccessedEntity Entity(AccessedEntity::Member, NamingClass,
811 DeclAccessPair::make(Dtor, Access));
John McCall58e6f342010-03-16 05:22:47 +0000812 Entity.setDiag(PDiag); // TODO: avoid copy
813
814 return CheckAccess(*this, Loc, Entity);
John McCall4f9506a2010-02-02 08:45:54 +0000815}
816
John McCallb13b7372010-02-01 03:16:54 +0000817/// Checks access to a constructor.
John McCall6b2accb2010-02-10 09:31:12 +0000818Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
John McCallb13b7372010-02-01 03:16:54 +0000819 CXXConstructorDecl *Constructor,
820 AccessSpecifier Access) {
John McCall58e6f342010-03-16 05:22:47 +0000821 if (!getLangOptions().AccessControl ||
822 Access == AS_public)
John McCall6b2accb2010-02-10 09:31:12 +0000823 return AR_accessible;
John McCallb13b7372010-02-01 03:16:54 +0000824
John McCall6b2accb2010-02-10 09:31:12 +0000825 CXXRecordDecl *NamingClass = Constructor->getParent();
John McCall9aa472c2010-03-19 07:35:19 +0000826 AccessedEntity Entity(AccessedEntity::Member, NamingClass,
827 DeclAccessPair::make(Constructor, Access));
John McCall58e6f342010-03-16 05:22:47 +0000828 Entity.setDiag(diag::err_access_ctor);
829
830 return CheckAccess(*this, UseLoc, Entity);
John McCallb13b7372010-02-01 03:16:54 +0000831}
832
John McCallb0207482010-03-16 06:11:48 +0000833/// Checks direct (i.e. non-inherited) access to an arbitrary class
834/// member.
835Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
836 NamedDecl *Target,
837 const PartialDiagnostic &Diag) {
838 AccessSpecifier Access = Target->getAccess();
839 if (!getLangOptions().AccessControl ||
840 Access == AS_public)
841 return AR_accessible;
842
843 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext());
John McCall9aa472c2010-03-19 07:35:19 +0000844 AccessedEntity Entity(AccessedEntity::Member, NamingClass,
845 DeclAccessPair::make(Target, Access));
John McCallb0207482010-03-16 06:11:48 +0000846 Entity.setDiag(Diag);
847 return CheckAccess(*this, UseLoc, Entity);
848}
849
850
John McCall90c8c572010-03-18 08:19:33 +0000851/// Checks access to an overloaded operator new or delete.
852Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
853 SourceRange PlacementRange,
854 CXXRecordDecl *NamingClass,
John McCall9aa472c2010-03-19 07:35:19 +0000855 DeclAccessPair Found) {
John McCall90c8c572010-03-18 08:19:33 +0000856 if (!getLangOptions().AccessControl ||
857 !NamingClass ||
John McCall9aa472c2010-03-19 07:35:19 +0000858 Found.getAccess() == AS_public)
John McCall90c8c572010-03-18 08:19:33 +0000859 return AR_accessible;
860
John McCall9aa472c2010-03-19 07:35:19 +0000861 AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found);
John McCall90c8c572010-03-18 08:19:33 +0000862 Entity.setDiag(diag::err_access)
863 << PlacementRange;
864
865 return CheckAccess(*this, OpLoc, Entity);
866}
867
John McCallb13b7372010-02-01 03:16:54 +0000868/// Checks access to an overloaded member operator, including
869/// conversion operators.
John McCall6b2accb2010-02-10 09:31:12 +0000870Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
871 Expr *ObjectExpr,
John McCall58e6f342010-03-16 05:22:47 +0000872 Expr *ArgExpr,
John McCall9aa472c2010-03-19 07:35:19 +0000873 DeclAccessPair Found) {
John McCall58e6f342010-03-16 05:22:47 +0000874 if (!getLangOptions().AccessControl ||
John McCall9aa472c2010-03-19 07:35:19 +0000875 Found.getAccess() == AS_public)
John McCall6b2accb2010-02-10 09:31:12 +0000876 return AR_accessible;
John McCall5357b612010-01-28 01:42:12 +0000877
878 const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
879 assert(RT && "found member operator but object expr not of record type");
880 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
881
John McCall9aa472c2010-03-19 07:35:19 +0000882 AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found);
John McCall58e6f342010-03-16 05:22:47 +0000883 Entity.setDiag(diag::err_access)
884 << ObjectExpr->getSourceRange()
885 << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
886
887 return CheckAccess(*this, OpLoc, Entity);
John McCall6b2accb2010-02-10 09:31:12 +0000888}
John McCall5357b612010-01-28 01:42:12 +0000889
John McCall6b2accb2010-02-10 09:31:12 +0000890/// Checks access for a hierarchy conversion.
891///
892/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
893/// or a derived-to-base conversion (false)
894/// \param ForceCheck true if this check should be performed even if access
895/// control is disabled; some things rely on this for semantics
896/// \param ForceUnprivileged true if this check should proceed as if the
897/// context had no special privileges
898/// \param ADK controls the kind of diagnostics that are used
899Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
John McCall6b2accb2010-02-10 09:31:12 +0000900 QualType Base,
901 QualType Derived,
902 const CXXBasePath &Path,
John McCall58e6f342010-03-16 05:22:47 +0000903 unsigned DiagID,
John McCall6b2accb2010-02-10 09:31:12 +0000904 bool ForceCheck,
John McCall58e6f342010-03-16 05:22:47 +0000905 bool ForceUnprivileged) {
John McCall6b2accb2010-02-10 09:31:12 +0000906 if (!ForceCheck && !getLangOptions().AccessControl)
907 return AR_accessible;
John McCall5357b612010-01-28 01:42:12 +0000908
John McCall6b2accb2010-02-10 09:31:12 +0000909 if (Path.Access == AS_public)
910 return AR_accessible;
John McCall5357b612010-01-28 01:42:12 +0000911
John McCall6b2accb2010-02-10 09:31:12 +0000912 CXXRecordDecl *BaseD, *DerivedD;
913 BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
914 DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
John McCall58e6f342010-03-16 05:22:47 +0000915
916 AccessedEntity Entity(AccessedEntity::Base, BaseD, DerivedD, Path.Access);
917 if (DiagID)
918 Entity.setDiag(DiagID) << Derived << Base;
John McCall6b2accb2010-02-10 09:31:12 +0000919
920 if (ForceUnprivileged)
John McCall58e6f342010-03-16 05:22:47 +0000921 return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity);
922 return CheckAccess(*this, AccessLoc, Entity);
John McCall5357b612010-01-28 01:42:12 +0000923}
924
John McCall92f88312010-01-23 00:46:32 +0000925/// Checks access to all the declarations in the given result set.
John McCall6b2accb2010-02-10 09:31:12 +0000926void Sema::CheckLookupAccess(const LookupResult &R) {
927 assert(getLangOptions().AccessControl
928 && "performing access check without access control");
929 assert(R.getNamingClass() && "performing access check without naming class");
930
John McCall58e6f342010-03-16 05:22:47 +0000931 for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
932 if (I.getAccess() != AS_public) {
933 AccessedEntity Entity(AccessedEntity::Member,
John McCall9aa472c2010-03-19 07:35:19 +0000934 R.getNamingClass(),
935 I.getPair());
John McCall58e6f342010-03-16 05:22:47 +0000936 Entity.setDiag(diag::err_access);
937
938 CheckAccess(*this, R.getNameLoc(), Entity);
939 }
940 }
John McCall92f88312010-01-23 00:46:32 +0000941}