blob: e7ea2041370cb5dc036a9f265626fd5ae7d6c586 [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 McCall2cc26752010-03-27 06:55:49 +000056 EffectiveContext() : Inner(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 McCall88b6c712010-03-17 04:58:56 +000062 // C++ [class.access.nest]p1:
63 // A nested class is a member and as such has the same access
64 // rights as any other member.
65 // C++ [class.access]p2:
66 // A member of a class can also access all the names to which
John McCall2cc26752010-03-27 06:55:49 +000067 // the class has access. A local class of a member function
68 // may access the same names that the member function itself
69 // may access.
70 // This almost implies that the privileges of nesting are transitive.
71 // Technically it says nothing about the local classes of non-member
72 // functions (which can gain privileges through friendship), but we
73 // take that as an oversight.
74 while (true) {
75 if (isa<CXXRecordDecl>(DC)) {
76 CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
77 Records.push_back(Record);
78 DC = Record->getDeclContext();
79 } else if (isa<FunctionDecl>(DC)) {
80 FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
81 Functions.push_back(Function);
82 DC = Function->getDeclContext();
83 } else if (DC->isFileContext()) {
84 break;
85 } else {
86 DC = DC->getParent();
87 }
John McCall88b6c712010-03-17 04:58:56 +000088 }
Anders Carlssonc4f1e872009-03-27 06:03:27 +000089 }
Sebastian Redl726212f2009-07-18 14:32:15 +000090
John McCall0c01d182010-03-24 05:22:00 +000091 bool isDependent() const { return Dependent; }
92
John McCall88b6c712010-03-17 04:58:56 +000093 bool includesClass(const CXXRecordDecl *R) const {
94 R = R->getCanonicalDecl();
95 return std::find(Records.begin(), Records.end(), R)
96 != Records.end();
John McCall6b2accb2010-02-10 09:31:12 +000097 }
98
John McCall7ad650f2010-03-24 07:46:06 +000099 /// Retrieves the innermost "useful" context. Can be null if we're
100 /// doing access-control without privileges.
101 DeclContext *getInnerContext() const {
102 return Inner;
John McCall0c01d182010-03-24 05:22:00 +0000103 }
104
105 typedef llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;
106
John McCall7ad650f2010-03-24 07:46:06 +0000107 DeclContext *Inner;
John McCall2cc26752010-03-27 06:55:49 +0000108 llvm::SmallVector<FunctionDecl*, 4> Functions;
John McCall88b6c712010-03-17 04:58:56 +0000109 llvm::SmallVector<CXXRecordDecl*, 4> Records;
John McCall0c01d182010-03-24 05:22:00 +0000110 bool Dependent;
John McCall6b2accb2010-02-10 09:31:12 +0000111};
Anders Carlsson29f006b2009-03-27 05:05:05 +0000112}
John McCall92f88312010-01-23 00:46:32 +0000113
John McCall6b2accb2010-02-10 09:31:12 +0000114static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
John McCallc1b621d2010-03-24 09:04:37 +0000115 DeclContext *DC = D->getDeclContext();
116
117 // This can only happen at top: enum decls only "publish" their
118 // immediate members.
119 if (isa<EnumDecl>(DC))
120 DC = cast<EnumDecl>(DC)->getDeclContext();
121
122 CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC);
John McCall6b2accb2010-02-10 09:31:12 +0000123 while (DeclaringClass->isAnonymousStructOrUnion())
124 DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
125 return DeclaringClass;
126}
127
John McCall0c01d182010-03-24 05:22:00 +0000128static bool MightInstantiateTo(Sema &S, DeclContext *Context,
129 DeclContext *Friend) {
130 if (Friend == Context)
131 return true;
132
133 assert(!Friend->isDependentContext() &&
134 "can't handle friends with dependent contexts here");
135
136 if (!Context->isDependentContext())
137 return false;
138
139 if (Friend->isFileContext())
140 return false;
141
142 // TODO: this is very conservative
143 return true;
144}
145
146// Asks whether the type in 'context' can ever instantiate to the type
147// in 'friend'.
148static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) {
149 if (Friend == Context)
150 return true;
151
152 if (!Friend->isDependentType() && !Context->isDependentType())
153 return false;
154
155 // TODO: this is very conservative.
156 return true;
157}
158
159static bool MightInstantiateTo(Sema &S,
160 FunctionDecl *Context,
161 FunctionDecl *Friend) {
162 if (Context->getDeclName() != Friend->getDeclName())
163 return false;
164
165 if (!MightInstantiateTo(S,
166 Context->getDeclContext(),
167 Friend->getDeclContext()))
168 return false;
169
170 CanQual<FunctionProtoType> FriendTy
171 = S.Context.getCanonicalType(Friend->getType())
172 ->getAs<FunctionProtoType>();
173 CanQual<FunctionProtoType> ContextTy
174 = S.Context.getCanonicalType(Context->getType())
175 ->getAs<FunctionProtoType>();
176
177 // There isn't any way that I know of to add qualifiers
178 // during instantiation.
179 if (FriendTy.getQualifiers() != ContextTy.getQualifiers())
180 return false;
181
182 if (FriendTy->getNumArgs() != ContextTy->getNumArgs())
183 return false;
184
185 if (!MightInstantiateTo(S,
186 ContextTy->getResultType(),
187 FriendTy->getResultType()))
188 return false;
189
190 for (unsigned I = 0, E = FriendTy->getNumArgs(); I != E; ++I)
191 if (!MightInstantiateTo(S,
192 ContextTy->getArgType(I),
193 FriendTy->getArgType(I)))
194 return false;
195
196 return true;
197}
198
199static bool MightInstantiateTo(Sema &S,
200 FunctionTemplateDecl *Context,
201 FunctionTemplateDecl *Friend) {
202 return MightInstantiateTo(S,
203 Context->getTemplatedDecl(),
204 Friend->getTemplatedDecl());
205}
206
John McCalla742db02010-03-17 20:01:29 +0000207static Sema::AccessResult MatchesFriend(Sema &S,
208 const EffectiveContext &EC,
209 const CXXRecordDecl *Friend) {
John McCalla742db02010-03-17 20:01:29 +0000210 if (EC.includesClass(Friend))
211 return Sema::AR_accessible;
212
John McCall0c01d182010-03-24 05:22:00 +0000213 if (EC.isDependent()) {
214 CanQualType FriendTy
215 = S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend));
216
217 for (EffectiveContext::record_iterator
218 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
219 CanQualType ContextTy
220 = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I));
221 if (MightInstantiateTo(S, ContextTy, FriendTy))
222 return Sema::AR_dependent;
223 }
224 }
225
John McCalla742db02010-03-17 20:01:29 +0000226 return Sema::AR_inaccessible;
227}
228
229static Sema::AccessResult MatchesFriend(Sema &S,
230 const EffectiveContext &EC,
John McCall0c01d182010-03-24 05:22:00 +0000231 CanQualType Friend) {
232 if (const RecordType *RT = Friend->getAs<RecordType>())
233 return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));
John McCalla742db02010-03-17 20:01:29 +0000234
John McCall0c01d182010-03-24 05:22:00 +0000235 // TODO: we can do better than this
236 if (Friend->isDependentType())
237 return Sema::AR_dependent;
John McCalla742db02010-03-17 20:01:29 +0000238
John McCall0c01d182010-03-24 05:22:00 +0000239 return Sema::AR_inaccessible;
240}
241
242/// Determines whether the given friend class template matches
243/// anything in the effective context.
244static Sema::AccessResult MatchesFriend(Sema &S,
245 const EffectiveContext &EC,
246 ClassTemplateDecl *Friend) {
247 Sema::AccessResult OnFailure = Sema::AR_inaccessible;
248
John McCall93ba8572010-03-25 06:39:04 +0000249 // Check whether the friend is the template of a class in the
250 // context chain.
John McCall0c01d182010-03-24 05:22:00 +0000251 for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
252 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
253 CXXRecordDecl *Record = *I;
254
John McCall93ba8572010-03-25 06:39:04 +0000255 // Figure out whether the current class has a template:
John McCall0c01d182010-03-24 05:22:00 +0000256 ClassTemplateDecl *CTD;
257
258 // A specialization of the template...
259 if (isa<ClassTemplateSpecializationDecl>(Record)) {
260 CTD = cast<ClassTemplateSpecializationDecl>(Record)
261 ->getSpecializedTemplate();
262
263 // ... or the template pattern itself.
264 } else {
265 CTD = Record->getDescribedClassTemplate();
266 if (!CTD) continue;
267 }
268
269 // It's a match.
270 if (Friend == CTD->getCanonicalDecl())
271 return Sema::AR_accessible;
272
John McCall93ba8572010-03-25 06:39:04 +0000273 // If the context isn't dependent, it can't be a dependent match.
274 if (!EC.isDependent())
275 continue;
276
John McCall0c01d182010-03-24 05:22:00 +0000277 // If the template names don't match, it can't be a dependent
278 // match. This isn't true in C++0x because of template aliases.
279 if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName())
280 continue;
281
282 // If the class's context can't instantiate to the friend's
283 // context, it can't be a dependent match.
284 if (!MightInstantiateTo(S, CTD->getDeclContext(),
285 Friend->getDeclContext()))
286 continue;
287
288 // Otherwise, it's a dependent match.
289 OnFailure = Sema::AR_dependent;
John McCalla742db02010-03-17 20:01:29 +0000290 }
291
John McCall0c01d182010-03-24 05:22:00 +0000292 return OnFailure;
293}
294
295/// Determines whether the given friend function matches anything in
296/// the effective context.
297static Sema::AccessResult MatchesFriend(Sema &S,
298 const EffectiveContext &EC,
299 FunctionDecl *Friend) {
John McCall2cc26752010-03-27 06:55:49 +0000300 Sema::AccessResult OnFailure = Sema::AR_inaccessible;
John McCall0c01d182010-03-24 05:22:00 +0000301
John McCall2cc26752010-03-27 06:55:49 +0000302 for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator
303 I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
304 if (Friend == *I)
305 return Sema::AR_accessible;
John McCall0c01d182010-03-24 05:22:00 +0000306
John McCall2cc26752010-03-27 06:55:49 +0000307 if (EC.isDependent() && MightInstantiateTo(S, *I, Friend))
308 OnFailure = Sema::AR_dependent;
309 }
John McCall0c01d182010-03-24 05:22:00 +0000310
John McCall2cc26752010-03-27 06:55:49 +0000311 return OnFailure;
John McCall0c01d182010-03-24 05:22:00 +0000312}
313
314/// Determines whether the given friend function template matches
315/// anything in the effective context.
316static Sema::AccessResult MatchesFriend(Sema &S,
317 const EffectiveContext &EC,
318 FunctionTemplateDecl *Friend) {
John McCall2cc26752010-03-27 06:55:49 +0000319 if (EC.Functions.empty()) return Sema::AR_inaccessible;
John McCall0c01d182010-03-24 05:22:00 +0000320
John McCall2cc26752010-03-27 06:55:49 +0000321 Sema::AccessResult OnFailure = Sema::AR_inaccessible;
John McCall0c01d182010-03-24 05:22:00 +0000322
John McCall2cc26752010-03-27 06:55:49 +0000323 for (llvm::SmallVectorImpl<FunctionDecl*>::const_iterator
324 I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) {
John McCall0c01d182010-03-24 05:22:00 +0000325
John McCall2cc26752010-03-27 06:55:49 +0000326 FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate();
327 if (!FTD)
328 FTD = (*I)->getDescribedFunctionTemplate();
329 if (!FTD)
330 continue;
John McCall0c01d182010-03-24 05:22:00 +0000331
John McCall2cc26752010-03-27 06:55:49 +0000332 FTD = FTD->getCanonicalDecl();
333
334 if (Friend == FTD)
335 return Sema::AR_accessible;
336
337 if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend))
338 OnFailure = Sema::AR_dependent;
339 }
340
341 return OnFailure;
John McCall0c01d182010-03-24 05:22:00 +0000342}
343
344/// Determines whether the given friend declaration matches anything
345/// in the effective context.
346static Sema::AccessResult MatchesFriend(Sema &S,
347 const EffectiveContext &EC,
348 FriendDecl *FriendD) {
John McCall32f2fb52010-03-25 18:04:51 +0000349 if (TypeSourceInfo *T = FriendD->getFriendType())
350 return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified());
John McCall0c01d182010-03-24 05:22:00 +0000351
352 NamedDecl *Friend
353 = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl());
John McCalla742db02010-03-17 20:01:29 +0000354
355 // FIXME: declarations with dependent or templated scope.
356
John McCall0c01d182010-03-24 05:22:00 +0000357 if (isa<ClassTemplateDecl>(Friend))
358 return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend));
John McCalla742db02010-03-17 20:01:29 +0000359
John McCall0c01d182010-03-24 05:22:00 +0000360 if (isa<FunctionTemplateDecl>(Friend))
361 return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend));
John McCalla742db02010-03-17 20:01:29 +0000362
John McCall0c01d182010-03-24 05:22:00 +0000363 if (isa<CXXRecordDecl>(Friend))
364 return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend));
John McCalla742db02010-03-17 20:01:29 +0000365
John McCall0c01d182010-03-24 05:22:00 +0000366 assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind");
367 return MatchesFriend(S, EC, cast<FunctionDecl>(Friend));
John McCalla742db02010-03-17 20:01:29 +0000368}
369
John McCall6b2accb2010-02-10 09:31:12 +0000370static Sema::AccessResult GetFriendKind(Sema &S,
371 const EffectiveContext &EC,
372 const CXXRecordDecl *Class) {
John McCalld60e22e2010-03-12 01:19:31 +0000373 // A class always has access to its own members.
John McCall88b6c712010-03-17 04:58:56 +0000374 if (EC.includesClass(Class))
John McCall6b2accb2010-02-10 09:31:12 +0000375 return Sema::AR_accessible;
376
John McCall88b6c712010-03-17 04:58:56 +0000377 Sema::AccessResult OnFailure = Sema::AR_inaccessible;
378
John McCalld60e22e2010-03-12 01:19:31 +0000379 // Okay, check friends.
380 for (CXXRecordDecl::friend_iterator I = Class->friend_begin(),
381 E = Class->friend_end(); I != E; ++I) {
382 FriendDecl *Friend = *I;
383
John McCalla742db02010-03-17 20:01:29 +0000384 switch (MatchesFriend(S, EC, Friend)) {
385 case Sema::AR_accessible:
386 return Sema::AR_accessible;
John McCalld60e22e2010-03-12 01:19:31 +0000387
John McCalla742db02010-03-17 20:01:29 +0000388 case Sema::AR_inaccessible:
389 break;
John McCall88b6c712010-03-17 04:58:56 +0000390
John McCalla742db02010-03-17 20:01:29 +0000391 case Sema::AR_dependent:
392 OnFailure = Sema::AR_dependent;
393 break;
394
395 case Sema::AR_delayed:
396 llvm_unreachable("cannot get delayed answer from MatchesFriend");
John McCalld60e22e2010-03-12 01:19:31 +0000397 }
John McCalld60e22e2010-03-12 01:19:31 +0000398 }
399
400 // That's it, give up.
John McCall88b6c712010-03-17 04:58:56 +0000401 return OnFailure;
John McCall6b2accb2010-02-10 09:31:12 +0000402}
403
404/// Finds the best path from the naming class to the declaring class,
405/// taking friend declarations into account.
406///
John McCall7aceaf82010-03-18 23:49:19 +0000407/// \param FinalAccess the access of the "final step", or AS_none if
408/// there is no final step.
John McCall6b2accb2010-02-10 09:31:12 +0000409/// \return null if friendship is dependent
410static CXXBasePath *FindBestPath(Sema &S,
411 const EffectiveContext &EC,
412 CXXRecordDecl *Derived,
413 CXXRecordDecl *Base,
John McCall7aceaf82010-03-18 23:49:19 +0000414 AccessSpecifier FinalAccess,
John McCall6b2accb2010-02-10 09:31:12 +0000415 CXXBasePaths &Paths) {
416 // Derive the paths to the desired base.
417 bool isDerived = Derived->isDerivedFrom(Base, Paths);
418 assert(isDerived && "derived class not actually derived from base");
419 (void) isDerived;
420
421 CXXBasePath *BestPath = 0;
422
John McCall7aceaf82010-03-18 23:49:19 +0000423 assert(FinalAccess != AS_none && "forbidden access after declaring class");
424
John McCall0c01d182010-03-24 05:22:00 +0000425 bool AnyDependent = false;
426
John McCall6b2accb2010-02-10 09:31:12 +0000427 // Derive the friend-modified access along each path.
428 for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
429 PI != PE; ++PI) {
430
431 // Walk through the path backwards.
John McCall7aceaf82010-03-18 23:49:19 +0000432 AccessSpecifier PathAccess = FinalAccess;
John McCall6b2accb2010-02-10 09:31:12 +0000433 CXXBasePath::iterator I = PI->end(), E = PI->begin();
434 while (I != E) {
435 --I;
436
John McCall7aceaf82010-03-18 23:49:19 +0000437 assert(PathAccess != AS_none);
438
439 // If the declaration is a private member of a base class, there
440 // is no level of friendship in derived classes that can make it
441 // accessible.
442 if (PathAccess == AS_private) {
443 PathAccess = AS_none;
444 break;
445 }
446
John McCall6b2accb2010-02-10 09:31:12 +0000447 AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
John McCalle06c1a12010-03-25 21:39:55 +0000448 if (BaseAccess != AS_public || PathAccess != AS_public) {
John McCall6b2accb2010-02-10 09:31:12 +0000449 switch (GetFriendKind(S, EC, I->Class)) {
John McCall7aceaf82010-03-18 23:49:19 +0000450 case Sema::AR_inaccessible:
451 PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess);
452 break;
453 case Sema::AR_accessible:
454 PathAccess = AS_public;
455 break;
456 case Sema::AR_dependent:
John McCall0c01d182010-03-24 05:22:00 +0000457 AnyDependent = true;
458 goto Next;
John McCall6b2accb2010-02-10 09:31:12 +0000459 case Sema::AR_delayed:
460 llvm_unreachable("friend resolution is never delayed"); break;
461 }
462 }
John McCall6b2accb2010-02-10 09:31:12 +0000463 }
464
465 // Note that we modify the path's Access field to the
466 // friend-modified access.
467 if (BestPath == 0 || PathAccess < BestPath->Access) {
468 BestPath = &*PI;
469 BestPath->Access = PathAccess;
John McCall0c01d182010-03-24 05:22:00 +0000470
471 // Short-circuit if we found a public path.
472 if (BestPath->Access == AS_public)
473 return BestPath;
John McCall6b2accb2010-02-10 09:31:12 +0000474 }
John McCall0c01d182010-03-24 05:22:00 +0000475
476 Next: ;
John McCall6b2accb2010-02-10 09:31:12 +0000477 }
478
John McCall0c01d182010-03-24 05:22:00 +0000479 assert((!BestPath || BestPath->Access != AS_public) &&
480 "fell out of loop with public path");
481
482 // We didn't find a public path, but at least one path was subject
483 // to dependent friendship, so delay the check.
484 if (AnyDependent)
485 return 0;
486
John McCall6b2accb2010-02-10 09:31:12 +0000487 return BestPath;
488}
489
490/// Diagnose the path which caused the given declaration or base class
491/// to become inaccessible.
492static void DiagnoseAccessPath(Sema &S,
493 const EffectiveContext &EC,
494 CXXRecordDecl *NamingClass,
495 CXXRecordDecl *DeclaringClass,
496 NamedDecl *D, AccessSpecifier Access) {
John McCall92f88312010-01-23 00:46:32 +0000497 // Easy case: the decl's natural access determined its path access.
John McCall6b2accb2010-02-10 09:31:12 +0000498 // We have to check against AS_private here in case Access is AS_none,
499 // indicating a non-public member of a private base class.
500 //
501 // DependentFriend should be impossible here.
502 if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
503 switch (GetFriendKind(S, EC, DeclaringClass)) {
504 case Sema::AR_inaccessible: {
505 S.Diag(D->getLocation(), diag::note_access_natural)
506 << (unsigned) (Access == AS_protected)
507 << /*FIXME: not implicitly*/ 0;
508 return;
509 }
510
511 case Sema::AR_accessible: break;
512
513 case Sema::AR_dependent:
514 case Sema::AR_delayed:
515 llvm_unreachable("dependent/delayed not allowed");
516 return;
517 }
518 }
519
520 CXXBasePaths Paths;
John McCall7aceaf82010-03-18 23:49:19 +0000521 CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass,
522 AS_public, Paths);
John McCall6b2accb2010-02-10 09:31:12 +0000523
524 CXXBasePath::iterator I = Path.end(), E = Path.begin();
525 while (I != E) {
526 --I;
527
528 const CXXBaseSpecifier *BS = I->Base;
529 AccessSpecifier BaseAccess = BS->getAccessSpecifier();
530
531 // If this is public inheritance, or the derived class is a friend,
532 // skip this step.
533 if (BaseAccess == AS_public)
534 continue;
535
536 switch (GetFriendKind(S, EC, I->Class)) {
537 case Sema::AR_accessible: continue;
538 case Sema::AR_inaccessible: break;
539
540 case Sema::AR_dependent:
541 case Sema::AR_delayed:
542 llvm_unreachable("dependent friendship, should not be diagnosing");
543 }
544
545 // Check whether this base specifier is the tighest point
546 // constraining access. We have to check against AS_private for
547 // the same reasons as above.
548 if (BaseAccess == AS_private || BaseAccess >= Access) {
549
550 // We're constrained by inheritance, but we want to say
551 // "declared private here" if we're diagnosing a hierarchy
552 // conversion and this is the final step.
553 unsigned diagnostic;
554 if (D) diagnostic = diag::note_access_constrained_by_path;
555 else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural;
556 else diagnostic = diag::note_access_constrained_by_path;
557
558 S.Diag(BS->getSourceRange().getBegin(), diagnostic)
559 << BS->getSourceRange()
560 << (BaseAccess == AS_protected)
561 << (BS->getAccessSpecifierAsWritten() == AS_none);
562 return;
563 }
564 }
565
566 llvm_unreachable("access not apparently constrained by path");
567}
568
569/// Diagnose an inaccessible class member.
570static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc,
571 const EffectiveContext &EC,
572 CXXRecordDecl *NamingClass,
573 AccessSpecifier Access,
574 const Sema::AccessedEntity &Entity) {
575 NamedDecl *D = Entity.getTargetDecl();
576 CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
577
John McCall58e6f342010-03-16 05:22:47 +0000578 S.Diag(Loc, Entity.getDiag())
579 << (Access == AS_protected)
580 << D->getDeclName()
581 << S.Context.getTypeDeclType(NamingClass)
582 << S.Context.getTypeDeclType(DeclaringClass);
John McCall6b2accb2010-02-10 09:31:12 +0000583 DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
584}
585
586/// Diagnose an inaccessible hierarchy conversion.
587static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc,
588 const EffectiveContext &EC,
589 AccessSpecifier Access,
John McCall58e6f342010-03-16 05:22:47 +0000590 const Sema::AccessedEntity &Entity) {
591 S.Diag(Loc, Entity.getDiag())
592 << (Access == AS_protected)
593 << DeclarationName()
594 << S.Context.getTypeDeclType(Entity.getDerivedClass())
595 << S.Context.getTypeDeclType(Entity.getBaseClass());
John McCall6b2accb2010-02-10 09:31:12 +0000596 DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
597 Entity.getBaseClass(), 0, Access);
598}
599
John McCall58e6f342010-03-16 05:22:47 +0000600static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
John McCall6b2accb2010-02-10 09:31:12 +0000601 const EffectiveContext &EC,
602 CXXRecordDecl *NamingClass,
603 AccessSpecifier Access,
John McCall58e6f342010-03-16 05:22:47 +0000604 const Sema::AccessedEntity &Entity) {
John McCall6b2accb2010-02-10 09:31:12 +0000605 if (Entity.isMemberAccess())
606 DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
607 else
John McCall58e6f342010-03-16 05:22:47 +0000608 DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity);
John McCall6b2accb2010-02-10 09:31:12 +0000609}
610
611
612/// Try to elevate access using friend declarations. This is
613/// potentially quite expensive.
John McCall0c01d182010-03-24 05:22:00 +0000614///
615/// \return true if elevation was dependent
616static bool TryElevateAccess(Sema &S,
John McCall6b2accb2010-02-10 09:31:12 +0000617 const EffectiveContext &EC,
618 const Sema::AccessedEntity &Entity,
619 AccessSpecifier &Access) {
620 CXXRecordDecl *DeclaringClass;
621 if (Entity.isMemberAccess()) {
622 DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
623 } else {
624 DeclaringClass = Entity.getBaseClass();
625 }
626 CXXRecordDecl *NamingClass = Entity.getNamingClass();
627
628 // Adjust the declaration of the referred entity.
John McCall7aceaf82010-03-18 23:49:19 +0000629 AccessSpecifier DeclAccess = AS_public;
John McCall6b2accb2010-02-10 09:31:12 +0000630 if (Entity.isMemberAccess()) {
631 NamedDecl *Target = Entity.getTargetDecl();
632
633 DeclAccess = Target->getAccess();
634 if (DeclAccess != AS_public) {
635 switch (GetFriendKind(S, EC, DeclaringClass)) {
636 case Sema::AR_accessible: DeclAccess = AS_public; break;
637 case Sema::AR_inaccessible: break;
John McCall0c01d182010-03-24 05:22:00 +0000638 case Sema::AR_dependent: return true;
John McCall6b2accb2010-02-10 09:31:12 +0000639 case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
640 }
641 }
642
643 if (DeclaringClass == NamingClass) {
644 Access = DeclAccess;
John McCall0c01d182010-03-24 05:22:00 +0000645 return false;
John McCall6b2accb2010-02-10 09:31:12 +0000646 }
647 }
648
649 assert(DeclaringClass != NamingClass);
650
651 // Append the declaration's access if applicable.
652 CXXBasePaths Paths;
653 CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(),
John McCall7aceaf82010-03-18 23:49:19 +0000654 DeclaringClass, DeclAccess, Paths);
John McCall0c01d182010-03-24 05:22:00 +0000655 if (!Path)
656 return true;
John McCall92f88312010-01-23 00:46:32 +0000657
John McCall7aceaf82010-03-18 23:49:19 +0000658 // Grab the access along the best path (note that this includes the
659 // final-step access).
John McCall6b2accb2010-02-10 09:31:12 +0000660 AccessSpecifier NewAccess = Path->Access;
John McCall6b2accb2010-02-10 09:31:12 +0000661 assert(NewAccess <= Access && "access along best path worse than direct?");
662 Access = NewAccess;
John McCall0c01d182010-03-24 05:22:00 +0000663 return false;
664}
665
666static void DelayAccess(Sema &S,
667 const EffectiveContext &EC,
668 SourceLocation Loc,
669 const Sema::AccessedEntity &Entity) {
670 assert(EC.isDependent() && "delaying non-dependent access");
John McCall7ad650f2010-03-24 07:46:06 +0000671 DeclContext *DC = EC.getInnerContext();
John McCall0c01d182010-03-24 05:22:00 +0000672 assert(DC->isDependentContext() && "delaying non-dependent access");
673 DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access,
674 Loc,
675 Entity.isMemberAccess(),
676 Entity.getAccess(),
677 Entity.getTargetDecl(),
678 Entity.getNamingClass(),
679 Entity.getDiag());
John McCall92f88312010-01-23 00:46:32 +0000680}
681
John McCall6b2accb2010-02-10 09:31:12 +0000682/// Checks access to an entity from the given effective context.
683static Sema::AccessResult CheckEffectiveAccess(Sema &S,
684 const EffectiveContext &EC,
685 SourceLocation Loc,
John McCall58e6f342010-03-16 05:22:47 +0000686 Sema::AccessedEntity const &Entity) {
John McCall6b2accb2010-02-10 09:31:12 +0000687 AccessSpecifier Access = Entity.getAccess();
John McCall88b6c712010-03-17 04:58:56 +0000688 assert(Access != AS_public && "called for public access!");
John McCall92f88312010-01-23 00:46:32 +0000689
John McCall88b6c712010-03-17 04:58:56 +0000690 // Find a non-anonymous naming class. For records with access,
691 // there should always be one of these.
John McCall6b2accb2010-02-10 09:31:12 +0000692 CXXRecordDecl *NamingClass = Entity.getNamingClass();
John McCall92f88312010-01-23 00:46:32 +0000693 while (NamingClass->isAnonymousStructOrUnion())
John McCall58e6f342010-03-16 05:22:47 +0000694 NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
John McCall92f88312010-01-23 00:46:32 +0000695
John McCall88b6c712010-03-17 04:58:56 +0000696 // White-list accesses from classes with privileges equivalent to the
697 // naming class --- but only if the access path isn't forbidden
698 // (i.e. an access of a private member from a subclass).
699 if (Access != AS_none && EC.includesClass(NamingClass))
John McCall6b2accb2010-02-10 09:31:12 +0000700 return Sema::AR_accessible;
John McCall88b6c712010-03-17 04:58:56 +0000701
702 // Try to elevate access.
John McCall88b6c712010-03-17 04:58:56 +0000703 // TODO: on some code, it might be better to do the protected check
704 // without trying to elevate first.
John McCall0c01d182010-03-24 05:22:00 +0000705 if (TryElevateAccess(S, EC, Entity, Access)) {
706 DelayAccess(S, EC, Loc, Entity);
707 return Sema::AR_dependent;
708 }
709
John McCall88b6c712010-03-17 04:58:56 +0000710 if (Access == AS_public) return Sema::AR_accessible;
John McCall92f88312010-01-23 00:46:32 +0000711
712 // Protected access.
713 if (Access == AS_protected) {
714 // FIXME: implement [class.protected]p1
John McCall88b6c712010-03-17 04:58:56 +0000715 for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
716 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I)
717 if ((*I)->isDerivedFrom(NamingClass))
718 return Sema::AR_accessible;
John McCall92f88312010-01-23 00:46:32 +0000719
John McCall88b6c712010-03-17 04:58:56 +0000720 // FIXME: delay if we can't decide class derivation yet.
John McCall92f88312010-01-23 00:46:32 +0000721 }
722
John McCall6b2accb2010-02-10 09:31:12 +0000723 // Okay, that's it, reject it.
John McCall58e6f342010-03-16 05:22:47 +0000724 if (!Entity.isQuiet())
725 DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
John McCall6b2accb2010-02-10 09:31:12 +0000726 return Sema::AR_inaccessible;
727}
John McCall92f88312010-01-23 00:46:32 +0000728
John McCall6b2accb2010-02-10 09:31:12 +0000729static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
John McCall58e6f342010-03-16 05:22:47 +0000730 const Sema::AccessedEntity &Entity) {
John McCall6b2accb2010-02-10 09:31:12 +0000731 // If the access path is public, it's accessible everywhere.
732 if (Entity.getAccess() == AS_public)
733 return Sema::AR_accessible;
John McCall92f88312010-01-23 00:46:32 +0000734
John McCall6b2accb2010-02-10 09:31:12 +0000735 // If we're currently parsing a top-level declaration, delay
736 // diagnostics. This is the only case where parsing a declaration
737 // can actually change our effective context for the purposes of
738 // access control.
739 if (S.CurContext->isFileContext() && S.ParsingDeclDepth) {
John McCall6b2accb2010-02-10 09:31:12 +0000740 S.DelayedDiagnostics.push_back(
741 Sema::DelayedDiagnostic::makeAccess(Loc, Entity));
742 return Sema::AR_delayed;
John McCall92f88312010-01-23 00:46:32 +0000743 }
744
John McCall6b2accb2010-02-10 09:31:12 +0000745 return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
John McCall58e6f342010-03-16 05:22:47 +0000746 Loc, Entity);
John McCall92f88312010-01-23 00:46:32 +0000747}
748
John McCall2f514482010-01-27 03:50:35 +0000749void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
John McCall2f514482010-01-27 03:50:35 +0000750 // Pretend we did this from the context of the newly-parsed
751 // declaration.
John McCall6b2accb2010-02-10 09:31:12 +0000752 EffectiveContext EC(Ctx->getDeclContext());
John McCall2f514482010-01-27 03:50:35 +0000753
John McCall58e6f342010-03-16 05:22:47 +0000754 if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData()))
John McCall2f514482010-01-27 03:50:35 +0000755 DD.Triggered = true;
756}
757
John McCall0c01d182010-03-24 05:22:00 +0000758void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,
759 const MultiLevelTemplateArgumentList &TemplateArgs) {
760 SourceLocation Loc = DD.getAccessLoc();
761 AccessSpecifier Access = DD.getAccess();
762
763 Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(),
764 TemplateArgs);
765 if (!NamingD) return;
766 Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(),
767 TemplateArgs);
768 if (!TargetD) return;
769
770 if (DD.isAccessToMember()) {
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000771 AccessedEntity Entity(Context,
772 AccessedEntity::Member,
John McCall0c01d182010-03-24 05:22:00 +0000773 cast<CXXRecordDecl>(NamingD),
774 Access,
775 cast<NamedDecl>(TargetD));
776 Entity.setDiag(DD.getDiagnostic());
777 CheckAccess(*this, Loc, Entity);
778 } else {
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000779 AccessedEntity Entity(Context,
780 AccessedEntity::Base,
John McCall0c01d182010-03-24 05:22:00 +0000781 cast<CXXRecordDecl>(TargetD),
782 cast<CXXRecordDecl>(NamingD),
783 Access);
784 Entity.setDiag(DD.getDiagnostic());
785 CheckAccess(*this, Loc, Entity);
786 }
787}
788
John McCall6b2accb2010-02-10 09:31:12 +0000789Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
John McCall9aa472c2010-03-19 07:35:19 +0000790 DeclAccessPair Found) {
John McCall58e6f342010-03-16 05:22:47 +0000791 if (!getLangOptions().AccessControl ||
792 !E->getNamingClass() ||
John McCall9aa472c2010-03-19 07:35:19 +0000793 Found.getAccess() == AS_public)
John McCall6b2accb2010-02-10 09:31:12 +0000794 return AR_accessible;
John McCallc373d482010-01-27 01:50:18 +0000795
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000796 AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(),
797 Found);
John McCall58e6f342010-03-16 05:22:47 +0000798 Entity.setDiag(diag::err_access) << E->getSourceRange();
799
800 return CheckAccess(*this, E->getNameLoc(), Entity);
John McCallc373d482010-01-27 01:50:18 +0000801}
802
803/// Perform access-control checking on a previously-unresolved member
804/// access which has now been resolved to a member.
John McCall6b2accb2010-02-10 09:31:12 +0000805Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
John McCall9aa472c2010-03-19 07:35:19 +0000806 DeclAccessPair Found) {
John McCall58e6f342010-03-16 05:22:47 +0000807 if (!getLangOptions().AccessControl ||
John McCall9aa472c2010-03-19 07:35:19 +0000808 Found.getAccess() == AS_public)
John McCall6b2accb2010-02-10 09:31:12 +0000809 return AR_accessible;
John McCallc373d482010-01-27 01:50:18 +0000810
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000811 AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(),
812 Found);
John McCall58e6f342010-03-16 05:22:47 +0000813 Entity.setDiag(diag::err_access) << E->getSourceRange();
814
815 return CheckAccess(*this, E->getMemberLoc(), Entity);
John McCallc373d482010-01-27 01:50:18 +0000816}
817
John McCall6b2accb2010-02-10 09:31:12 +0000818Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
John McCall58e6f342010-03-16 05:22:47 +0000819 CXXDestructorDecl *Dtor,
820 const PartialDiagnostic &PDiag) {
John McCall4f9506a2010-02-02 08:45:54 +0000821 if (!getLangOptions().AccessControl)
John McCall6b2accb2010-02-10 09:31:12 +0000822 return AR_accessible;
John McCall4f9506a2010-02-02 08:45:54 +0000823
John McCall58e6f342010-03-16 05:22:47 +0000824 // There's never a path involved when checking implicit destructor access.
John McCall4f9506a2010-02-02 08:45:54 +0000825 AccessSpecifier Access = Dtor->getAccess();
826 if (Access == AS_public)
John McCall6b2accb2010-02-10 09:31:12 +0000827 return AR_accessible;
John McCall4f9506a2010-02-02 08:45:54 +0000828
John McCall58e6f342010-03-16 05:22:47 +0000829 CXXRecordDecl *NamingClass = Dtor->getParent();
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000830 AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
John McCall9aa472c2010-03-19 07:35:19 +0000831 DeclAccessPair::make(Dtor, Access));
John McCall58e6f342010-03-16 05:22:47 +0000832 Entity.setDiag(PDiag); // TODO: avoid copy
833
834 return CheckAccess(*this, Loc, Entity);
John McCall4f9506a2010-02-02 08:45:54 +0000835}
836
John McCallb13b7372010-02-01 03:16:54 +0000837/// Checks access to a constructor.
John McCall6b2accb2010-02-10 09:31:12 +0000838Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
John McCallb13b7372010-02-01 03:16:54 +0000839 CXXConstructorDecl *Constructor,
840 AccessSpecifier Access) {
John McCall58e6f342010-03-16 05:22:47 +0000841 if (!getLangOptions().AccessControl ||
842 Access == AS_public)
John McCall6b2accb2010-02-10 09:31:12 +0000843 return AR_accessible;
John McCallb13b7372010-02-01 03:16:54 +0000844
John McCall6b2accb2010-02-10 09:31:12 +0000845 CXXRecordDecl *NamingClass = Constructor->getParent();
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000846 AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
John McCall9aa472c2010-03-19 07:35:19 +0000847 DeclAccessPair::make(Constructor, Access));
John McCall58e6f342010-03-16 05:22:47 +0000848 Entity.setDiag(diag::err_access_ctor);
849
850 return CheckAccess(*this, UseLoc, Entity);
John McCallb13b7372010-02-01 03:16:54 +0000851}
852
John McCallb0207482010-03-16 06:11:48 +0000853/// Checks direct (i.e. non-inherited) access to an arbitrary class
854/// member.
855Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
856 NamedDecl *Target,
857 const PartialDiagnostic &Diag) {
858 AccessSpecifier Access = Target->getAccess();
859 if (!getLangOptions().AccessControl ||
860 Access == AS_public)
861 return AR_accessible;
862
863 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext());
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000864 AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
John McCall9aa472c2010-03-19 07:35:19 +0000865 DeclAccessPair::make(Target, Access));
John McCallb0207482010-03-16 06:11:48 +0000866 Entity.setDiag(Diag);
867 return CheckAccess(*this, UseLoc, Entity);
868}
869
870
John McCall90c8c572010-03-18 08:19:33 +0000871/// Checks access to an overloaded operator new or delete.
872Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
873 SourceRange PlacementRange,
874 CXXRecordDecl *NamingClass,
John McCall9aa472c2010-03-19 07:35:19 +0000875 DeclAccessPair Found) {
John McCall90c8c572010-03-18 08:19:33 +0000876 if (!getLangOptions().AccessControl ||
877 !NamingClass ||
John McCall9aa472c2010-03-19 07:35:19 +0000878 Found.getAccess() == AS_public)
John McCall90c8c572010-03-18 08:19:33 +0000879 return AR_accessible;
880
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000881 AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
John McCall90c8c572010-03-18 08:19:33 +0000882 Entity.setDiag(diag::err_access)
883 << PlacementRange;
884
885 return CheckAccess(*this, OpLoc, Entity);
886}
887
John McCallb13b7372010-02-01 03:16:54 +0000888/// Checks access to an overloaded member operator, including
889/// conversion operators.
John McCall6b2accb2010-02-10 09:31:12 +0000890Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
891 Expr *ObjectExpr,
John McCall58e6f342010-03-16 05:22:47 +0000892 Expr *ArgExpr,
John McCall9aa472c2010-03-19 07:35:19 +0000893 DeclAccessPair Found) {
John McCall58e6f342010-03-16 05:22:47 +0000894 if (!getLangOptions().AccessControl ||
John McCall9aa472c2010-03-19 07:35:19 +0000895 Found.getAccess() == AS_public)
John McCall6b2accb2010-02-10 09:31:12 +0000896 return AR_accessible;
John McCall5357b612010-01-28 01:42:12 +0000897
898 const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
899 assert(RT && "found member operator but object expr not of record type");
900 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
901
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000902 AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
John McCall58e6f342010-03-16 05:22:47 +0000903 Entity.setDiag(diag::err_access)
904 << ObjectExpr->getSourceRange()
905 << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
906
907 return CheckAccess(*this, OpLoc, Entity);
John McCall6b2accb2010-02-10 09:31:12 +0000908}
John McCall5357b612010-01-28 01:42:12 +0000909
John McCall6b2accb2010-02-10 09:31:12 +0000910/// Checks access for a hierarchy conversion.
911///
912/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
913/// or a derived-to-base conversion (false)
914/// \param ForceCheck true if this check should be performed even if access
915/// control is disabled; some things rely on this for semantics
916/// \param ForceUnprivileged true if this check should proceed as if the
917/// context had no special privileges
918/// \param ADK controls the kind of diagnostics that are used
919Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
John McCall6b2accb2010-02-10 09:31:12 +0000920 QualType Base,
921 QualType Derived,
922 const CXXBasePath &Path,
John McCall58e6f342010-03-16 05:22:47 +0000923 unsigned DiagID,
John McCall6b2accb2010-02-10 09:31:12 +0000924 bool ForceCheck,
John McCall58e6f342010-03-16 05:22:47 +0000925 bool ForceUnprivileged) {
John McCall6b2accb2010-02-10 09:31:12 +0000926 if (!ForceCheck && !getLangOptions().AccessControl)
927 return AR_accessible;
John McCall5357b612010-01-28 01:42:12 +0000928
John McCall6b2accb2010-02-10 09:31:12 +0000929 if (Path.Access == AS_public)
930 return AR_accessible;
John McCall5357b612010-01-28 01:42:12 +0000931
John McCall6b2accb2010-02-10 09:31:12 +0000932 CXXRecordDecl *BaseD, *DerivedD;
933 BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
934 DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
John McCall58e6f342010-03-16 05:22:47 +0000935
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000936 AccessedEntity Entity(Context, AccessedEntity::Base, BaseD, DerivedD,
937 Path.Access);
John McCall58e6f342010-03-16 05:22:47 +0000938 if (DiagID)
939 Entity.setDiag(DiagID) << Derived << Base;
John McCall6b2accb2010-02-10 09:31:12 +0000940
941 if (ForceUnprivileged)
John McCall58e6f342010-03-16 05:22:47 +0000942 return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity);
943 return CheckAccess(*this, AccessLoc, Entity);
John McCall5357b612010-01-28 01:42:12 +0000944}
945
John McCall92f88312010-01-23 00:46:32 +0000946/// Checks access to all the declarations in the given result set.
John McCall6b2accb2010-02-10 09:31:12 +0000947void Sema::CheckLookupAccess(const LookupResult &R) {
948 assert(getLangOptions().AccessControl
949 && "performing access check without access control");
950 assert(R.getNamingClass() && "performing access check without naming class");
951
John McCall58e6f342010-03-16 05:22:47 +0000952 for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
953 if (I.getAccess() != AS_public) {
Douglas Gregorfe6b2d42010-03-29 23:34:08 +0000954 AccessedEntity Entity(Context, AccessedEntity::Member,
John McCall9aa472c2010-03-19 07:35:19 +0000955 R.getNamingClass(),
956 I.getPair());
John McCall58e6f342010-03-16 05:22:47 +0000957 Entity.setDiag(diag::err_access);
958
959 CheckAccess(*this, R.getNameLoc(), Entity);
960 }
961 }
John McCall92f88312010-01-23 00:46:32 +0000962}