blob: f628884aab42e8d90f4f5024d710153338063dfb [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 McCall3dc81f72010-03-27 06:55:49 +000056 EffectiveContext() : Inner(0), Dependent(false) {}
Anders Carlsson733d77f2009-03-27 06:03:27 +000057
John McCall816d75b2010-03-24 07:46:06 +000058 explicit EffectiveContext(DeclContext *DC)
59 : Inner(DC),
60 Dependent(DC->isDependentContext()) {
John McCallc62bb642010-03-24 05:22:00 +000061
John McCallfb803d72010-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 McCall3dc81f72010-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 McCallfb803d72010-03-17 04:58:56 +000088 }
Anders Carlsson733d77f2009-03-27 06:03:27 +000089 }
Sebastian Redle644e192009-07-18 14:32:15 +000090
John McCallc62bb642010-03-24 05:22:00 +000091 bool isDependent() const { return Dependent; }
92
John McCallfb803d72010-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 McCall5b0829a2010-02-10 09:31:12 +000097 }
98
John McCall816d75b2010-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 McCallc62bb642010-03-24 05:22:00 +0000103 }
104
105 typedef llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator;
106
John McCall816d75b2010-03-24 07:46:06 +0000107 DeclContext *Inner;
John McCall3dc81f72010-03-27 06:55:49 +0000108 llvm::SmallVector<FunctionDecl*, 4> Functions;
John McCallfb803d72010-03-17 04:58:56 +0000109 llvm::SmallVector<CXXRecordDecl*, 4> Records;
John McCallc62bb642010-03-24 05:22:00 +0000110 bool Dependent;
John McCall5b0829a2010-02-10 09:31:12 +0000111};
Anders Carlsson4742a9c2009-03-27 05:05:05 +0000112}
John McCall553c0792010-01-23 00:46:32 +0000113
John McCall5b0829a2010-02-10 09:31:12 +0000114static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
John McCall69f75862010-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 McCall5b0829a2010-02-10 09:31:12 +0000123 while (DeclaringClass->isAnonymousStructOrUnion())
124 DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
125 return DeclaringClass;
126}
127
John McCallc62bb642010-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 McCall39e82882010-03-17 20:01:29 +0000207static Sema::AccessResult MatchesFriend(Sema &S,
208 const EffectiveContext &EC,
209 const CXXRecordDecl *Friend) {
John McCall39e82882010-03-17 20:01:29 +0000210 if (EC.includesClass(Friend))
211 return Sema::AR_accessible;
212
John McCallc62bb642010-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 McCall39e82882010-03-17 20:01:29 +0000226 return Sema::AR_inaccessible;
227}
228
229static Sema::AccessResult MatchesFriend(Sema &S,
230 const EffectiveContext &EC,
John McCallc62bb642010-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 McCall39e82882010-03-17 20:01:29 +0000234
John McCallc62bb642010-03-24 05:22:00 +0000235 // TODO: we can do better than this
236 if (Friend->isDependentType())
237 return Sema::AR_dependent;
John McCall39e82882010-03-17 20:01:29 +0000238
John McCallc62bb642010-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 McCall598b4402010-03-25 06:39:04 +0000249 // Check whether the friend is the template of a class in the
250 // context chain.
John McCallc62bb642010-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 McCall598b4402010-03-25 06:39:04 +0000255 // Figure out whether the current class has a template:
John McCallc62bb642010-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 McCall598b4402010-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 McCallc62bb642010-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 McCall39e82882010-03-17 20:01:29 +0000290 }
291
John McCallc62bb642010-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 McCall3dc81f72010-03-27 06:55:49 +0000300 Sema::AccessResult OnFailure = Sema::AR_inaccessible;
John McCallc62bb642010-03-24 05:22:00 +0000301
John McCall3dc81f72010-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 McCallc62bb642010-03-24 05:22:00 +0000306
John McCall3dc81f72010-03-27 06:55:49 +0000307 if (EC.isDependent() && MightInstantiateTo(S, *I, Friend))
308 OnFailure = Sema::AR_dependent;
309 }
John McCallc62bb642010-03-24 05:22:00 +0000310
John McCall3dc81f72010-03-27 06:55:49 +0000311 return OnFailure;
John McCallc62bb642010-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 McCall3dc81f72010-03-27 06:55:49 +0000319 if (EC.Functions.empty()) return Sema::AR_inaccessible;
John McCallc62bb642010-03-24 05:22:00 +0000320
John McCall3dc81f72010-03-27 06:55:49 +0000321 Sema::AccessResult OnFailure = Sema::AR_inaccessible;
John McCallc62bb642010-03-24 05:22:00 +0000322
John McCall3dc81f72010-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 McCallc62bb642010-03-24 05:22:00 +0000325
John McCall3dc81f72010-03-27 06:55:49 +0000326 FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate();
327 if (!FTD)
328 FTD = (*I)->getDescribedFunctionTemplate();
329 if (!FTD)
330 continue;
John McCallc62bb642010-03-24 05:22:00 +0000331
John McCall3dc81f72010-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 McCallc62bb642010-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 McCall15ad0962010-03-25 18:04:51 +0000349 if (TypeSourceInfo *T = FriendD->getFriendType())
350 return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified());
John McCallc62bb642010-03-24 05:22:00 +0000351
352 NamedDecl *Friend
353 = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl());
John McCall39e82882010-03-17 20:01:29 +0000354
355 // FIXME: declarations with dependent or templated scope.
356
John McCallc62bb642010-03-24 05:22:00 +0000357 if (isa<ClassTemplateDecl>(Friend))
358 return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend));
John McCall39e82882010-03-17 20:01:29 +0000359
John McCallc62bb642010-03-24 05:22:00 +0000360 if (isa<FunctionTemplateDecl>(Friend))
361 return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend));
John McCall39e82882010-03-17 20:01:29 +0000362
John McCallc62bb642010-03-24 05:22:00 +0000363 if (isa<CXXRecordDecl>(Friend))
364 return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend));
John McCall39e82882010-03-17 20:01:29 +0000365
John McCallc62bb642010-03-24 05:22:00 +0000366 assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind");
367 return MatchesFriend(S, EC, cast<FunctionDecl>(Friend));
John McCall39e82882010-03-17 20:01:29 +0000368}
369
John McCall5b0829a2010-02-10 09:31:12 +0000370static Sema::AccessResult GetFriendKind(Sema &S,
371 const EffectiveContext &EC,
372 const CXXRecordDecl *Class) {
John McCallfb803d72010-03-17 04:58:56 +0000373 Sema::AccessResult OnFailure = Sema::AR_inaccessible;
374
John McCall16927f62010-03-12 01:19:31 +0000375 // Okay, check friends.
376 for (CXXRecordDecl::friend_iterator I = Class->friend_begin(),
377 E = Class->friend_end(); I != E; ++I) {
378 FriendDecl *Friend = *I;
379
John McCall39e82882010-03-17 20:01:29 +0000380 switch (MatchesFriend(S, EC, Friend)) {
381 case Sema::AR_accessible:
382 return Sema::AR_accessible;
John McCall16927f62010-03-12 01:19:31 +0000383
John McCall39e82882010-03-17 20:01:29 +0000384 case Sema::AR_inaccessible:
385 break;
John McCallfb803d72010-03-17 04:58:56 +0000386
John McCall39e82882010-03-17 20:01:29 +0000387 case Sema::AR_dependent:
388 OnFailure = Sema::AR_dependent;
389 break;
390
391 case Sema::AR_delayed:
392 llvm_unreachable("cannot get delayed answer from MatchesFriend");
John McCall16927f62010-03-12 01:19:31 +0000393 }
John McCall16927f62010-03-12 01:19:31 +0000394 }
395
396 // That's it, give up.
John McCallfb803d72010-03-17 04:58:56 +0000397 return OnFailure;
John McCall5b0829a2010-02-10 09:31:12 +0000398}
399
John McCalld79b4d82010-04-02 00:03:43 +0000400static Sema::AccessResult HasAccess(Sema &S,
401 const EffectiveContext &EC,
402 const CXXRecordDecl *NamingClass,
403 AccessSpecifier Access) {
404 assert(NamingClass->getCanonicalDecl() == NamingClass &&
405 "declaration should be canonicalized before being passed here");
406
407 if (Access == AS_public) return Sema::AR_accessible;
408 assert(Access == AS_private || Access == AS_protected);
409
410 for (EffectiveContext::record_iterator
411 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
412 // All the declarations in EC have been canonicalized, so pointer
413 // equality from this point on will work fine.
414 const CXXRecordDecl *ECRecord = *I;
415
416 // [B2] and [M2]
417 if (ECRecord == NamingClass)
418 return Sema::AR_accessible;
419
420 // [B3] and [M3]
421 if (Access == AS_protected &&
422 ECRecord->isDerivedFrom(const_cast<CXXRecordDecl*>(NamingClass)))
423 return Sema::AR_accessible;
424 }
425
426 return GetFriendKind(S, EC, NamingClass);
427}
428
John McCall5b0829a2010-02-10 09:31:12 +0000429/// Finds the best path from the naming class to the declaring class,
430/// taking friend declarations into account.
431///
John McCalld79b4d82010-04-02 00:03:43 +0000432/// C++0x [class.access.base]p5:
433/// A member m is accessible at the point R when named in class N if
434/// [M1] m as a member of N is public, or
435/// [M2] m as a member of N is private, and R occurs in a member or
436/// friend of class N, or
437/// [M3] m as a member of N is protected, and R occurs in a member or
438/// friend of class N, or in a member or friend of a class P
439/// derived from N, where m as a member of P is public, private,
440/// or protected, or
441/// [M4] there exists a base class B of N that is accessible at R, and
442/// m is accessible at R when named in class B.
443///
444/// C++0x [class.access.base]p4:
445/// A base class B of N is accessible at R, if
446/// [B1] an invented public member of B would be a public member of N, or
447/// [B2] R occurs in a member or friend of class N, and an invented public
448/// member of B would be a private or protected member of N, or
449/// [B3] R occurs in a member or friend of a class P derived from N, and an
450/// invented public member of B would be a private or protected member
451/// of P, or
452/// [B4] there exists a class S such that B is a base class of S accessible
453/// at R and S is a base class of N accessible at R.
454///
455/// Along a single inheritance path we can restate both of these
456/// iteratively:
457///
458/// First, we note that M1-4 are equivalent to B1-4 if the member is
459/// treated as a notional base of its declaring class with inheritance
460/// access equivalent to the member's access. Therefore we need only
461/// ask whether a class B is accessible from a class N in context R.
462///
463/// Let B_1 .. B_n be the inheritance path in question (i.e. where
464/// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of
465/// B_i). For i in 1..n, we will calculate ACAB(i), the access to the
466/// closest accessible base in the path:
467/// Access(a, b) = (* access on the base specifier from a to b *)
468/// Merge(a, forbidden) = forbidden
469/// Merge(a, private) = forbidden
470/// Merge(a, b) = min(a,b)
471/// Accessible(c, forbidden) = false
472/// Accessible(c, private) = (R is c) || IsFriend(c, R)
473/// Accessible(c, protected) = (R derived from c) || IsFriend(c, R)
474/// Accessible(c, public) = true
475/// ACAB(n) = public
476/// ACAB(i) =
477/// let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in
478/// if Accessible(B_i, AccessToBase) then public else AccessToBase
479///
480/// B is an accessible base of N at R iff ACAB(1) = public.
481///
John McCalla332b952010-03-18 23:49:19 +0000482/// \param FinalAccess the access of the "final step", or AS_none if
483/// there is no final step.
John McCall5b0829a2010-02-10 09:31:12 +0000484/// \return null if friendship is dependent
485static CXXBasePath *FindBestPath(Sema &S,
486 const EffectiveContext &EC,
487 CXXRecordDecl *Derived,
488 CXXRecordDecl *Base,
John McCalla332b952010-03-18 23:49:19 +0000489 AccessSpecifier FinalAccess,
John McCall5b0829a2010-02-10 09:31:12 +0000490 CXXBasePaths &Paths) {
491 // Derive the paths to the desired base.
492 bool isDerived = Derived->isDerivedFrom(Base, Paths);
493 assert(isDerived && "derived class not actually derived from base");
494 (void) isDerived;
495
496 CXXBasePath *BestPath = 0;
497
John McCalla332b952010-03-18 23:49:19 +0000498 assert(FinalAccess != AS_none && "forbidden access after declaring class");
499
John McCallc62bb642010-03-24 05:22:00 +0000500 bool AnyDependent = false;
501
John McCall5b0829a2010-02-10 09:31:12 +0000502 // Derive the friend-modified access along each path.
503 for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
504 PI != PE; ++PI) {
505
506 // Walk through the path backwards.
John McCalla332b952010-03-18 23:49:19 +0000507 AccessSpecifier PathAccess = FinalAccess;
John McCall5b0829a2010-02-10 09:31:12 +0000508 CXXBasePath::iterator I = PI->end(), E = PI->begin();
509 while (I != E) {
510 --I;
511
John McCalla332b952010-03-18 23:49:19 +0000512 assert(PathAccess != AS_none);
513
514 // If the declaration is a private member of a base class, there
515 // is no level of friendship in derived classes that can make it
516 // accessible.
517 if (PathAccess == AS_private) {
518 PathAccess = AS_none;
519 break;
520 }
521
John McCall5b0829a2010-02-10 09:31:12 +0000522 AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
John McCalld79b4d82010-04-02 00:03:43 +0000523 PathAccess = std::max(PathAccess, BaseAccess);
524 switch (HasAccess(S, EC, I->Class, PathAccess)) {
525 case Sema::AR_inaccessible: break;
526 case Sema::AR_accessible: PathAccess = AS_public; break;
527 case Sema::AR_dependent:
528 AnyDependent = true;
529 goto Next;
530 case Sema::AR_delayed:
531 llvm_unreachable("friend resolution is never delayed"); break;
John McCall5b0829a2010-02-10 09:31:12 +0000532 }
John McCall5b0829a2010-02-10 09:31:12 +0000533 }
534
535 // Note that we modify the path's Access field to the
536 // friend-modified access.
537 if (BestPath == 0 || PathAccess < BestPath->Access) {
538 BestPath = &*PI;
539 BestPath->Access = PathAccess;
John McCallc62bb642010-03-24 05:22:00 +0000540
541 // Short-circuit if we found a public path.
542 if (BestPath->Access == AS_public)
543 return BestPath;
John McCall5b0829a2010-02-10 09:31:12 +0000544 }
John McCallc62bb642010-03-24 05:22:00 +0000545
546 Next: ;
John McCall5b0829a2010-02-10 09:31:12 +0000547 }
548
John McCallc62bb642010-03-24 05:22:00 +0000549 assert((!BestPath || BestPath->Access != AS_public) &&
550 "fell out of loop with public path");
551
552 // We didn't find a public path, but at least one path was subject
553 // to dependent friendship, so delay the check.
554 if (AnyDependent)
555 return 0;
556
John McCall5b0829a2010-02-10 09:31:12 +0000557 return BestPath;
558}
559
560/// Diagnose the path which caused the given declaration or base class
561/// to become inaccessible.
562static void DiagnoseAccessPath(Sema &S,
563 const EffectiveContext &EC,
John McCalld79b4d82010-04-02 00:03:43 +0000564 const Sema::AccessedEntity &Entity) {
565 AccessSpecifier Access = Entity.getAccess();
566 CXXRecordDecl *NamingClass = Entity.getNamingClass();
567 NamingClass = NamingClass->getCanonicalDecl();
568
569 NamedDecl *D;
570 CXXRecordDecl *DeclaringClass;
571 if (Entity.isMemberAccess()) {
572 D = Entity.getTargetDecl();
573 DeclaringClass = FindDeclaringClass(D);
574 } else {
575 D = 0;
576 DeclaringClass = Entity.getBaseClass();
577 }
578 DeclaringClass = DeclaringClass->getCanonicalDecl();
579
John McCall553c0792010-01-23 00:46:32 +0000580 // Easy case: the decl's natural access determined its path access.
John McCall5b0829a2010-02-10 09:31:12 +0000581 // We have to check against AS_private here in case Access is AS_none,
582 // indicating a non-public member of a private base class.
John McCall5b0829a2010-02-10 09:31:12 +0000583 if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
John McCalld79b4d82010-04-02 00:03:43 +0000584 switch (HasAccess(S, EC, DeclaringClass, D->getAccess())) {
John McCall5b0829a2010-02-10 09:31:12 +0000585 case Sema::AR_inaccessible: {
586 S.Diag(D->getLocation(), diag::note_access_natural)
587 << (unsigned) (Access == AS_protected)
588 << /*FIXME: not implicitly*/ 0;
589 return;
590 }
591
592 case Sema::AR_accessible: break;
593
594 case Sema::AR_dependent:
595 case Sema::AR_delayed:
596 llvm_unreachable("dependent/delayed not allowed");
597 return;
598 }
599 }
600
601 CXXBasePaths Paths;
John McCalla332b952010-03-18 23:49:19 +0000602 CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass,
603 AS_public, Paths);
John McCall5b0829a2010-02-10 09:31:12 +0000604
605 CXXBasePath::iterator I = Path.end(), E = Path.begin();
606 while (I != E) {
607 --I;
608
609 const CXXBaseSpecifier *BS = I->Base;
610 AccessSpecifier BaseAccess = BS->getAccessSpecifier();
611
612 // If this is public inheritance, or the derived class is a friend,
613 // skip this step.
614 if (BaseAccess == AS_public)
615 continue;
616
617 switch (GetFriendKind(S, EC, I->Class)) {
618 case Sema::AR_accessible: continue;
619 case Sema::AR_inaccessible: break;
620
621 case Sema::AR_dependent:
622 case Sema::AR_delayed:
623 llvm_unreachable("dependent friendship, should not be diagnosing");
624 }
625
626 // Check whether this base specifier is the tighest point
627 // constraining access. We have to check against AS_private for
628 // the same reasons as above.
629 if (BaseAccess == AS_private || BaseAccess >= Access) {
630
631 // We're constrained by inheritance, but we want to say
632 // "declared private here" if we're diagnosing a hierarchy
633 // conversion and this is the final step.
634 unsigned diagnostic;
635 if (D) diagnostic = diag::note_access_constrained_by_path;
636 else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural;
637 else diagnostic = diag::note_access_constrained_by_path;
638
639 S.Diag(BS->getSourceRange().getBegin(), diagnostic)
640 << BS->getSourceRange()
641 << (BaseAccess == AS_protected)
642 << (BS->getAccessSpecifierAsWritten() == AS_none);
643 return;
644 }
645 }
646
647 llvm_unreachable("access not apparently constrained by path");
648}
649
John McCall1064d7e2010-03-16 05:22:47 +0000650static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
John McCall5b0829a2010-02-10 09:31:12 +0000651 const EffectiveContext &EC,
John McCall1064d7e2010-03-16 05:22:47 +0000652 const Sema::AccessedEntity &Entity) {
John McCalld79b4d82010-04-02 00:03:43 +0000653 const CXXRecordDecl *NamingClass = Entity.getNamingClass();
654 NamedDecl *D;
655 const CXXRecordDecl *DeclaringClass;
656 if (Entity.isMemberAccess()) {
657 D = Entity.getTargetDecl();
658 DeclaringClass = FindDeclaringClass(D);
659 } else {
660 D = 0;
661 DeclaringClass = Entity.getBaseClass();
662 }
663
664 S.Diag(Loc, Entity.getDiag())
665 << (Entity.getAccess() == AS_protected)
666 << (D ? D->getDeclName() : DeclarationName())
667 << S.Context.getTypeDeclType(NamingClass)
668 << S.Context.getTypeDeclType(DeclaringClass);
669 DiagnoseAccessPath(S, EC, Entity);
John McCall5b0829a2010-02-10 09:31:12 +0000670}
671
John McCalld79b4d82010-04-02 00:03:43 +0000672/// Determines whether the accessed entity is accessible. Public members
673/// have been weeded out by this point.
674static Sema::AccessResult IsAccessible(Sema &S,
675 const EffectiveContext &EC,
676 const Sema::AccessedEntity &Entity) {
677 // Determine the actual naming class.
678 CXXRecordDecl *NamingClass = Entity.getNamingClass();
679 while (NamingClass->isAnonymousStructOrUnion())
680 NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
681 NamingClass = NamingClass->getCanonicalDecl();
John McCall5b0829a2010-02-10 09:31:12 +0000682
John McCalld79b4d82010-04-02 00:03:43 +0000683 AccessSpecifier UnprivilegedAccess = Entity.getAccess();
684 assert(UnprivilegedAccess != AS_public && "public access not weeded out");
685
686 // Before we try to recalculate access paths, try to white-list
687 // accesses which just trade in on the final step, i.e. accesses
688 // which don't require [M4] or [B4]. These are by far the most
689 // common forms of access.
690 if (UnprivilegedAccess != AS_none) {
691 switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess)) {
692 case Sema::AR_dependent:
693 // This is actually an interesting policy decision. We don't
694 // *have* to delay immediately here: we can do the full access
695 // calculation in the hope that friendship on some intermediate
696 // class will make the declaration accessible non-dependently.
697 // But that's not cheap, and odds are very good (note: assertion
698 // made without data) that the friend declaration will determine
699 // access.
700 return Sema::AR_dependent;
701
702 case Sema::AR_accessible: return Sema::AR_accessible;
703 case Sema::AR_inaccessible: break;
704 case Sema::AR_delayed:
705 llvm_unreachable("friendship never subject to contextual delay");
706 }
707 }
708
709 // Determine the declaring class.
John McCall5b0829a2010-02-10 09:31:12 +0000710 CXXRecordDecl *DeclaringClass;
711 if (Entity.isMemberAccess()) {
712 DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
713 } else {
714 DeclaringClass = Entity.getBaseClass();
715 }
John McCalld79b4d82010-04-02 00:03:43 +0000716 DeclaringClass = DeclaringClass->getCanonicalDecl();
John McCall5b0829a2010-02-10 09:31:12 +0000717
John McCalld79b4d82010-04-02 00:03:43 +0000718 // We lower member accesses to base accesses by pretending that the
719 // member is a base class of its declaring class.
720 AccessSpecifier FinalAccess;
721
John McCall5b0829a2010-02-10 09:31:12 +0000722 if (Entity.isMemberAccess()) {
John McCalld79b4d82010-04-02 00:03:43 +0000723 // Determine if the declaration is accessible from EC when named
724 // in its declaring class.
John McCall5b0829a2010-02-10 09:31:12 +0000725 NamedDecl *Target = Entity.getTargetDecl();
726
John McCalld79b4d82010-04-02 00:03:43 +0000727 FinalAccess = Target->getAccess();
728 switch (HasAccess(S, EC, DeclaringClass, FinalAccess)) {
729 case Sema::AR_accessible: FinalAccess = AS_public; break;
730 case Sema::AR_inaccessible: break;
731 case Sema::AR_dependent: return Sema::AR_dependent; // see above
732 case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
John McCall5b0829a2010-02-10 09:31:12 +0000733 }
734
John McCalld79b4d82010-04-02 00:03:43 +0000735 if (DeclaringClass == NamingClass)
736 return (FinalAccess == AS_public
737 ? Sema::AR_accessible
738 : Sema::AR_inaccessible);
739 } else {
740 FinalAccess = AS_public;
John McCall5b0829a2010-02-10 09:31:12 +0000741 }
742
743 assert(DeclaringClass != NamingClass);
744
745 // Append the declaration's access if applicable.
746 CXXBasePaths Paths;
John McCalld79b4d82010-04-02 00:03:43 +0000747 CXXBasePath *Path = FindBestPath(S, EC, NamingClass, DeclaringClass,
748 FinalAccess, Paths);
John McCallc62bb642010-03-24 05:22:00 +0000749 if (!Path)
John McCalld79b4d82010-04-02 00:03:43 +0000750 return Sema::AR_dependent;
John McCall553c0792010-01-23 00:46:32 +0000751
John McCalld79b4d82010-04-02 00:03:43 +0000752 assert(Path->Access <= UnprivilegedAccess &&
753 "access along best path worse than direct?");
754 if (Path->Access == AS_public)
755 return Sema::AR_accessible;
756 return Sema::AR_inaccessible;
John McCallc62bb642010-03-24 05:22:00 +0000757}
758
759static void DelayAccess(Sema &S,
760 const EffectiveContext &EC,
761 SourceLocation Loc,
762 const Sema::AccessedEntity &Entity) {
763 assert(EC.isDependent() && "delaying non-dependent access");
John McCall816d75b2010-03-24 07:46:06 +0000764 DeclContext *DC = EC.getInnerContext();
John McCallc62bb642010-03-24 05:22:00 +0000765 assert(DC->isDependentContext() && "delaying non-dependent access");
766 DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access,
767 Loc,
768 Entity.isMemberAccess(),
769 Entity.getAccess(),
770 Entity.getTargetDecl(),
771 Entity.getNamingClass(),
772 Entity.getDiag());
John McCall553c0792010-01-23 00:46:32 +0000773}
774
John McCall5b0829a2010-02-10 09:31:12 +0000775/// Checks access to an entity from the given effective context.
776static Sema::AccessResult CheckEffectiveAccess(Sema &S,
777 const EffectiveContext &EC,
778 SourceLocation Loc,
John McCalld79b4d82010-04-02 00:03:43 +0000779 const Sema::AccessedEntity &Entity) {
780 assert(Entity.getAccess() != AS_public && "called for public access!");
John McCall553c0792010-01-23 00:46:32 +0000781
John McCalld79b4d82010-04-02 00:03:43 +0000782 switch (IsAccessible(S, EC, Entity)) {
783 case Sema::AR_dependent:
John McCallc62bb642010-03-24 05:22:00 +0000784 DelayAccess(S, EC, Loc, Entity);
785 return Sema::AR_dependent;
John McCalld79b4d82010-04-02 00:03:43 +0000786
787 case Sema::AR_delayed:
788 llvm_unreachable("IsAccessible cannot contextually delay");
789
790 case Sema::AR_inaccessible:
791 if (!Entity.isQuiet())
792 DiagnoseBadAccess(S, Loc, EC, Entity);
793 return Sema::AR_inaccessible;
794
795 case Sema::AR_accessible:
796 break;
John McCallc62bb642010-03-24 05:22:00 +0000797 }
798
John McCalld79b4d82010-04-02 00:03:43 +0000799 // We only consider the natural access of the declaration when
800 // deciding whether to do the protected check.
801 if (Entity.isMemberAccess() && Entity.getAccess() == AS_protected) {
802 NamedDecl *D = Entity.getTargetDecl();
803 if (isa<FieldDecl>(D) ||
804 (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())) {
805 // FIXME: implement [class.protected]
806 }
John McCall553c0792010-01-23 00:46:32 +0000807 }
808
John McCalld79b4d82010-04-02 00:03:43 +0000809 return Sema::AR_accessible;
John McCall5b0829a2010-02-10 09:31:12 +0000810}
John McCall553c0792010-01-23 00:46:32 +0000811
John McCall5b0829a2010-02-10 09:31:12 +0000812static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
John McCall1064d7e2010-03-16 05:22:47 +0000813 const Sema::AccessedEntity &Entity) {
John McCall5b0829a2010-02-10 09:31:12 +0000814 // If the access path is public, it's accessible everywhere.
815 if (Entity.getAccess() == AS_public)
816 return Sema::AR_accessible;
John McCall553c0792010-01-23 00:46:32 +0000817
John McCall5b0829a2010-02-10 09:31:12 +0000818 // If we're currently parsing a top-level declaration, delay
819 // diagnostics. This is the only case where parsing a declaration
820 // can actually change our effective context for the purposes of
821 // access control.
822 if (S.CurContext->isFileContext() && S.ParsingDeclDepth) {
John McCall5b0829a2010-02-10 09:31:12 +0000823 S.DelayedDiagnostics.push_back(
824 Sema::DelayedDiagnostic::makeAccess(Loc, Entity));
825 return Sema::AR_delayed;
John McCall553c0792010-01-23 00:46:32 +0000826 }
827
John McCall5b0829a2010-02-10 09:31:12 +0000828 return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
John McCall1064d7e2010-03-16 05:22:47 +0000829 Loc, Entity);
John McCall553c0792010-01-23 00:46:32 +0000830}
831
John McCall86121512010-01-27 03:50:35 +0000832void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
John McCall86121512010-01-27 03:50:35 +0000833 // Pretend we did this from the context of the newly-parsed
834 // declaration.
John McCall5b0829a2010-02-10 09:31:12 +0000835 EffectiveContext EC(Ctx->getDeclContext());
John McCall86121512010-01-27 03:50:35 +0000836
John McCall1064d7e2010-03-16 05:22:47 +0000837 if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData()))
John McCall86121512010-01-27 03:50:35 +0000838 DD.Triggered = true;
839}
840
John McCallc62bb642010-03-24 05:22:00 +0000841void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD,
842 const MultiLevelTemplateArgumentList &TemplateArgs) {
843 SourceLocation Loc = DD.getAccessLoc();
844 AccessSpecifier Access = DD.getAccess();
845
846 Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(),
847 TemplateArgs);
848 if (!NamingD) return;
849 Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(),
850 TemplateArgs);
851 if (!TargetD) return;
852
853 if (DD.isAccessToMember()) {
Douglas Gregor89336232010-03-29 23:34:08 +0000854 AccessedEntity Entity(Context,
855 AccessedEntity::Member,
John McCallc62bb642010-03-24 05:22:00 +0000856 cast<CXXRecordDecl>(NamingD),
857 Access,
858 cast<NamedDecl>(TargetD));
859 Entity.setDiag(DD.getDiagnostic());
860 CheckAccess(*this, Loc, Entity);
861 } else {
Douglas Gregor89336232010-03-29 23:34:08 +0000862 AccessedEntity Entity(Context,
863 AccessedEntity::Base,
John McCallc62bb642010-03-24 05:22:00 +0000864 cast<CXXRecordDecl>(TargetD),
865 cast<CXXRecordDecl>(NamingD),
866 Access);
867 Entity.setDiag(DD.getDiagnostic());
868 CheckAccess(*this, Loc, Entity);
869 }
870}
871
John McCall5b0829a2010-02-10 09:31:12 +0000872Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
John McCalla0296f72010-03-19 07:35:19 +0000873 DeclAccessPair Found) {
John McCall1064d7e2010-03-16 05:22:47 +0000874 if (!getLangOptions().AccessControl ||
875 !E->getNamingClass() ||
John McCalla0296f72010-03-19 07:35:19 +0000876 Found.getAccess() == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000877 return AR_accessible;
John McCall58cc69d2010-01-27 01:50:18 +0000878
Douglas Gregor89336232010-03-29 23:34:08 +0000879 AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(),
880 Found);
John McCall1064d7e2010-03-16 05:22:47 +0000881 Entity.setDiag(diag::err_access) << E->getSourceRange();
882
883 return CheckAccess(*this, E->getNameLoc(), Entity);
John McCall58cc69d2010-01-27 01:50:18 +0000884}
885
886/// Perform access-control checking on a previously-unresolved member
887/// access which has now been resolved to a member.
John McCall5b0829a2010-02-10 09:31:12 +0000888Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
John McCalla0296f72010-03-19 07:35:19 +0000889 DeclAccessPair Found) {
John McCall1064d7e2010-03-16 05:22:47 +0000890 if (!getLangOptions().AccessControl ||
John McCalla0296f72010-03-19 07:35:19 +0000891 Found.getAccess() == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000892 return AR_accessible;
John McCall58cc69d2010-01-27 01:50:18 +0000893
Douglas Gregor89336232010-03-29 23:34:08 +0000894 AccessedEntity Entity(Context, AccessedEntity::Member, E->getNamingClass(),
895 Found);
John McCall1064d7e2010-03-16 05:22:47 +0000896 Entity.setDiag(diag::err_access) << E->getSourceRange();
897
898 return CheckAccess(*this, E->getMemberLoc(), Entity);
John McCall58cc69d2010-01-27 01:50:18 +0000899}
900
John McCall5b0829a2010-02-10 09:31:12 +0000901Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
John McCall1064d7e2010-03-16 05:22:47 +0000902 CXXDestructorDecl *Dtor,
903 const PartialDiagnostic &PDiag) {
John McCall6781b052010-02-02 08:45:54 +0000904 if (!getLangOptions().AccessControl)
John McCall5b0829a2010-02-10 09:31:12 +0000905 return AR_accessible;
John McCall6781b052010-02-02 08:45:54 +0000906
John McCall1064d7e2010-03-16 05:22:47 +0000907 // There's never a path involved when checking implicit destructor access.
John McCall6781b052010-02-02 08:45:54 +0000908 AccessSpecifier Access = Dtor->getAccess();
909 if (Access == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000910 return AR_accessible;
John McCall6781b052010-02-02 08:45:54 +0000911
John McCall1064d7e2010-03-16 05:22:47 +0000912 CXXRecordDecl *NamingClass = Dtor->getParent();
Douglas Gregor89336232010-03-29 23:34:08 +0000913 AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
John McCalla0296f72010-03-19 07:35:19 +0000914 DeclAccessPair::make(Dtor, Access));
John McCall1064d7e2010-03-16 05:22:47 +0000915 Entity.setDiag(PDiag); // TODO: avoid copy
916
917 return CheckAccess(*this, Loc, Entity);
John McCall6781b052010-02-02 08:45:54 +0000918}
919
John McCall760af172010-02-01 03:16:54 +0000920/// Checks access to a constructor.
John McCall5b0829a2010-02-10 09:31:12 +0000921Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
John McCall760af172010-02-01 03:16:54 +0000922 CXXConstructorDecl *Constructor,
923 AccessSpecifier Access) {
John McCall1064d7e2010-03-16 05:22:47 +0000924 if (!getLangOptions().AccessControl ||
925 Access == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000926 return AR_accessible;
John McCall760af172010-02-01 03:16:54 +0000927
John McCall5b0829a2010-02-10 09:31:12 +0000928 CXXRecordDecl *NamingClass = Constructor->getParent();
Douglas Gregor89336232010-03-29 23:34:08 +0000929 AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
John McCalla0296f72010-03-19 07:35:19 +0000930 DeclAccessPair::make(Constructor, Access));
John McCall1064d7e2010-03-16 05:22:47 +0000931 Entity.setDiag(diag::err_access_ctor);
932
933 return CheckAccess(*this, UseLoc, Entity);
John McCall760af172010-02-01 03:16:54 +0000934}
935
John McCallab8c2732010-03-16 06:11:48 +0000936/// Checks direct (i.e. non-inherited) access to an arbitrary class
937/// member.
938Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
939 NamedDecl *Target,
940 const PartialDiagnostic &Diag) {
941 AccessSpecifier Access = Target->getAccess();
942 if (!getLangOptions().AccessControl ||
943 Access == AS_public)
944 return AR_accessible;
945
946 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext());
Douglas Gregor89336232010-03-29 23:34:08 +0000947 AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass,
John McCalla0296f72010-03-19 07:35:19 +0000948 DeclAccessPair::make(Target, Access));
John McCallab8c2732010-03-16 06:11:48 +0000949 Entity.setDiag(Diag);
950 return CheckAccess(*this, UseLoc, Entity);
951}
952
953
John McCallfb6f5262010-03-18 08:19:33 +0000954/// Checks access to an overloaded operator new or delete.
955Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
956 SourceRange PlacementRange,
957 CXXRecordDecl *NamingClass,
John McCalla0296f72010-03-19 07:35:19 +0000958 DeclAccessPair Found) {
John McCallfb6f5262010-03-18 08:19:33 +0000959 if (!getLangOptions().AccessControl ||
960 !NamingClass ||
John McCalla0296f72010-03-19 07:35:19 +0000961 Found.getAccess() == AS_public)
John McCallfb6f5262010-03-18 08:19:33 +0000962 return AR_accessible;
963
Douglas Gregor89336232010-03-29 23:34:08 +0000964 AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
John McCallfb6f5262010-03-18 08:19:33 +0000965 Entity.setDiag(diag::err_access)
966 << PlacementRange;
967
968 return CheckAccess(*this, OpLoc, Entity);
969}
970
John McCall760af172010-02-01 03:16:54 +0000971/// Checks access to an overloaded member operator, including
972/// conversion operators.
John McCall5b0829a2010-02-10 09:31:12 +0000973Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
974 Expr *ObjectExpr,
John McCall1064d7e2010-03-16 05:22:47 +0000975 Expr *ArgExpr,
John McCalla0296f72010-03-19 07:35:19 +0000976 DeclAccessPair Found) {
John McCall1064d7e2010-03-16 05:22:47 +0000977 if (!getLangOptions().AccessControl ||
John McCalla0296f72010-03-19 07:35:19 +0000978 Found.getAccess() == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000979 return AR_accessible;
John McCallb3a44002010-01-28 01:42:12 +0000980
981 const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
982 assert(RT && "found member operator but object expr not of record type");
983 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
984
Douglas Gregor89336232010-03-29 23:34:08 +0000985 AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
John McCall1064d7e2010-03-16 05:22:47 +0000986 Entity.setDiag(diag::err_access)
987 << ObjectExpr->getSourceRange()
988 << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
989
990 return CheckAccess(*this, OpLoc, Entity);
John McCall5b0829a2010-02-10 09:31:12 +0000991}
John McCallb3a44002010-01-28 01:42:12 +0000992
John McCall16df1e52010-03-30 21:47:33 +0000993Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr,
994 DeclAccessPair Found) {
995 if (!getLangOptions().AccessControl ||
John McCallb493d532010-03-30 22:20:00 +0000996 Found.getAccess() == AS_none ||
John McCall16df1e52010-03-30 21:47:33 +0000997 Found.getAccess() == AS_public)
998 return AR_accessible;
999
1000 OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).getPointer();
1001 NestedNameSpecifier *Qualifier = Ovl->getQualifier();
1002 assert(Qualifier && "address of overloaded member without qualifier");
1003
1004 CXXScopeSpec SS;
1005 SS.setScopeRep(Qualifier);
1006 SS.setRange(Ovl->getQualifierRange());
1007 DeclContext *DC = computeDeclContext(SS);
1008 assert(DC && DC->isRecord() && "scope did not resolve to record");
1009 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(DC);
1010
1011 AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found);
1012 Entity.setDiag(diag::err_access)
1013 << Ovl->getSourceRange();
1014
1015 return CheckAccess(*this, Ovl->getNameLoc(), Entity);
1016}
1017
1018
John McCall5b0829a2010-02-10 09:31:12 +00001019/// Checks access for a hierarchy conversion.
1020///
1021/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
1022/// or a derived-to-base conversion (false)
1023/// \param ForceCheck true if this check should be performed even if access
1024/// control is disabled; some things rely on this for semantics
1025/// \param ForceUnprivileged true if this check should proceed as if the
1026/// context had no special privileges
1027/// \param ADK controls the kind of diagnostics that are used
1028Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
John McCall5b0829a2010-02-10 09:31:12 +00001029 QualType Base,
1030 QualType Derived,
1031 const CXXBasePath &Path,
John McCall1064d7e2010-03-16 05:22:47 +00001032 unsigned DiagID,
John McCall5b0829a2010-02-10 09:31:12 +00001033 bool ForceCheck,
John McCall1064d7e2010-03-16 05:22:47 +00001034 bool ForceUnprivileged) {
John McCall5b0829a2010-02-10 09:31:12 +00001035 if (!ForceCheck && !getLangOptions().AccessControl)
1036 return AR_accessible;
John McCallb3a44002010-01-28 01:42:12 +00001037
John McCall5b0829a2010-02-10 09:31:12 +00001038 if (Path.Access == AS_public)
1039 return AR_accessible;
John McCallb3a44002010-01-28 01:42:12 +00001040
John McCall5b0829a2010-02-10 09:31:12 +00001041 CXXRecordDecl *BaseD, *DerivedD;
1042 BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
1043 DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
John McCall1064d7e2010-03-16 05:22:47 +00001044
Douglas Gregor89336232010-03-29 23:34:08 +00001045 AccessedEntity Entity(Context, AccessedEntity::Base, BaseD, DerivedD,
1046 Path.Access);
John McCall1064d7e2010-03-16 05:22:47 +00001047 if (DiagID)
1048 Entity.setDiag(DiagID) << Derived << Base;
John McCall5b0829a2010-02-10 09:31:12 +00001049
1050 if (ForceUnprivileged)
John McCall1064d7e2010-03-16 05:22:47 +00001051 return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity);
1052 return CheckAccess(*this, AccessLoc, Entity);
John McCallb3a44002010-01-28 01:42:12 +00001053}
1054
John McCall553c0792010-01-23 00:46:32 +00001055/// Checks access to all the declarations in the given result set.
John McCall5b0829a2010-02-10 09:31:12 +00001056void Sema::CheckLookupAccess(const LookupResult &R) {
1057 assert(getLangOptions().AccessControl
1058 && "performing access check without access control");
1059 assert(R.getNamingClass() && "performing access check without naming class");
1060
John McCall1064d7e2010-03-16 05:22:47 +00001061 for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
1062 if (I.getAccess() != AS_public) {
Douglas Gregor89336232010-03-29 23:34:08 +00001063 AccessedEntity Entity(Context, AccessedEntity::Member,
John McCalla0296f72010-03-19 07:35:19 +00001064 R.getNamingClass(),
1065 I.getPair());
John McCall1064d7e2010-03-16 05:22:47 +00001066 Entity.setDiag(diag::err_access);
1067
1068 CheckAccess(*this, R.getNameLoc(), Entity);
1069 }
1070 }
John McCall553c0792010-01-23 00:46:32 +00001071}