blob: 40b320c1be5e4f25684449daea39b95712b7fcc5 [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 McCall58cc69d2010-01-27 01:50:18 +000020#include "clang/AST/ExprCXX.h"
21
Anders Carlsson17941122009-03-27 04:54:36 +000022using namespace clang;
23
Anders Carlsson4742a9c2009-03-27 05:05:05 +000024/// SetMemberAccessSpecifier - Set the access specifier of a member.
25/// Returns true on error (when the previous member decl access specifier
26/// is different from the new member decl access specifier).
Mike Stump11289f42009-09-09 15:08:12 +000027bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
Anders Carlsson17941122009-03-27 04:54:36 +000028 NamedDecl *PrevMemberDecl,
29 AccessSpecifier LexicalAS) {
30 if (!PrevMemberDecl) {
31 // Use the lexical access specifier.
32 MemberDecl->setAccess(LexicalAS);
33 return false;
34 }
Mike Stump11289f42009-09-09 15:08:12 +000035
Anders Carlsson17941122009-03-27 04:54:36 +000036 // C++ [class.access.spec]p3: When a member is redeclared its access
37 // specifier must be same as its initial declaration.
38 if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) {
Mike Stump11289f42009-09-09 15:08:12 +000039 Diag(MemberDecl->getLocation(),
40 diag::err_class_redeclared_with_different_access)
Anders Carlsson17941122009-03-27 04:54:36 +000041 << MemberDecl << LexicalAS;
42 Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)
43 << PrevMemberDecl << PrevMemberDecl->getAccess();
John McCall0a4bb262009-12-23 00:37:40 +000044
45 MemberDecl->setAccess(LexicalAS);
Anders Carlsson17941122009-03-27 04:54:36 +000046 return true;
47 }
Mike Stump11289f42009-09-09 15:08:12 +000048
Anders Carlsson17941122009-03-27 04:54:36 +000049 MemberDecl->setAccess(PrevMemberDecl->getAccess());
50 return false;
51}
Anders Carlsson4742a9c2009-03-27 05:05:05 +000052
John McCall5b0829a2010-02-10 09:31:12 +000053namespace {
54struct EffectiveContext {
John McCallfb803d72010-03-17 04:58:56 +000055 EffectiveContext() : Function(0) {}
Anders Carlsson733d77f2009-03-27 06:03:27 +000056
John McCall5b0829a2010-02-10 09:31:12 +000057 explicit EffectiveContext(DeclContext *DC) {
58 if (isa<FunctionDecl>(DC)) {
John McCall16927f62010-03-12 01:19:31 +000059 Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
John McCall5b0829a2010-02-10 09:31:12 +000060 DC = Function->getDeclContext();
61 } else
62 Function = 0;
John McCallfb803d72010-03-17 04:58:56 +000063
64 // C++ [class.access.nest]p1:
65 // A nested class is a member and as such has the same access
66 // rights as any other member.
67 // C++ [class.access]p2:
68 // A member of a class can also access all the names to which
69 // the class has access.
70 // This implies that the privileges of nesting are transitive.
71 while (isa<CXXRecordDecl>(DC)) {
72 CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
73 Records.push_back(Record);
74 DC = Record->getDeclContext();
75 }
Anders Carlsson733d77f2009-03-27 06:03:27 +000076 }
Sebastian Redle644e192009-07-18 14:32:15 +000077
John McCallfb803d72010-03-17 04:58:56 +000078 bool includesClass(const CXXRecordDecl *R) const {
79 R = R->getCanonicalDecl();
80 return std::find(Records.begin(), Records.end(), R)
81 != Records.end();
John McCall5b0829a2010-02-10 09:31:12 +000082 }
83
John McCallfb803d72010-03-17 04:58:56 +000084 llvm::SmallVector<CXXRecordDecl*, 4> Records;
John McCall5b0829a2010-02-10 09:31:12 +000085 FunctionDecl *Function;
86};
Anders Carlsson4742a9c2009-03-27 05:05:05 +000087}
John McCall553c0792010-01-23 00:46:32 +000088
John McCall5b0829a2010-02-10 09:31:12 +000089static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
90 CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
91 while (DeclaringClass->isAnonymousStructOrUnion())
92 DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
93 return DeclaringClass;
94}
95
John McCall39e82882010-03-17 20:01:29 +000096static Sema::AccessResult MatchesFriend(Sema &S,
97 const EffectiveContext &EC,
98 const CXXRecordDecl *Friend) {
99 // FIXME: close matches becuse of dependency
100 if (EC.includesClass(Friend))
101 return Sema::AR_accessible;
102
103 return Sema::AR_inaccessible;
104}
105
106static Sema::AccessResult MatchesFriend(Sema &S,
107 const EffectiveContext &EC,
108 FriendDecl *Friend) {
109 if (Type *T = Friend->getFriendType()) {
110 CanQualType CT = T->getCanonicalTypeUnqualified();
111 if (const RecordType *RT = CT->getAs<RecordType>())
112 return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl()));
113
114 // TODO: we can fail early for a lot of type classes.
115 if (T->isDependentType())
116 return Sema::AR_dependent;
117
118 return Sema::AR_inaccessible;
119 }
120
121 NamedDecl *D
122 = cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl());
123
124 // FIXME: declarations with dependent or templated scope.
125
126 // For class templates, we want to check whether any of the records
127 // are possible specializations of the template.
128 if (isa<ClassTemplateDecl>(D)) {
129 for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
130 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
131 CXXRecordDecl *Record = *I;
132 ClassTemplateDecl *CTD;
133
134 // A specialization of the template...
135 if (isa<ClassTemplateSpecializationDecl>(Record)) {
136 CTD = cast<ClassTemplateSpecializationDecl>(Record)
137 ->getSpecializedTemplate();
138
139 // ... or the template pattern itself.
140 } else {
141 CTD = Record->getDescribedClassTemplate();
142 }
143
144 if (CTD && D == CTD->getCanonicalDecl())
145 return Sema::AR_accessible;
146 }
147
148 return Sema::AR_inaccessible;
149 }
150
151 // Same thing for function templates.
152 if (isa<FunctionTemplateDecl>(D)) {
153 if (!EC.Function) return Sema::AR_inaccessible;
154
155 FunctionTemplateDecl *FTD = EC.Function->getPrimaryTemplate();
156 if (!FTD)
157 FTD = EC.Function->getDescribedFunctionTemplate();
158
159 if (FTD && D == FTD->getCanonicalDecl())
160 return Sema::AR_accessible;
161
162 return Sema::AR_inaccessible;
163 }
164
165 // Friend functions. FIXME: close matches due to dependency.
166 //
167 // The decl pointers in EC have been canonicalized, so pointer
168 // equality is sufficient.
169 if (D == EC.Function)
170 return Sema::AR_accessible;
171
172 if (isa<CXXRecordDecl>(D))
173 return MatchesFriend(S, EC, cast<CXXRecordDecl>(D));
174
175 return Sema::AR_inaccessible;
176}
177
John McCall5b0829a2010-02-10 09:31:12 +0000178static Sema::AccessResult GetFriendKind(Sema &S,
179 const EffectiveContext &EC,
180 const CXXRecordDecl *Class) {
John McCall16927f62010-03-12 01:19:31 +0000181 // A class always has access to its own members.
John McCallfb803d72010-03-17 04:58:56 +0000182 if (EC.includesClass(Class))
John McCall5b0829a2010-02-10 09:31:12 +0000183 return Sema::AR_accessible;
184
John McCallfb803d72010-03-17 04:58:56 +0000185 Sema::AccessResult OnFailure = Sema::AR_inaccessible;
186
John McCall16927f62010-03-12 01:19:31 +0000187 // Okay, check friends.
188 for (CXXRecordDecl::friend_iterator I = Class->friend_begin(),
189 E = Class->friend_end(); I != E; ++I) {
190 FriendDecl *Friend = *I;
191
John McCall39e82882010-03-17 20:01:29 +0000192 switch (MatchesFriend(S, EC, Friend)) {
193 case Sema::AR_accessible:
194 return Sema::AR_accessible;
John McCall16927f62010-03-12 01:19:31 +0000195
John McCall39e82882010-03-17 20:01:29 +0000196 case Sema::AR_inaccessible:
197 break;
John McCallfb803d72010-03-17 04:58:56 +0000198
John McCall39e82882010-03-17 20:01:29 +0000199 case Sema::AR_dependent:
200 OnFailure = Sema::AR_dependent;
201 break;
202
203 case Sema::AR_delayed:
204 llvm_unreachable("cannot get delayed answer from MatchesFriend");
John McCall16927f62010-03-12 01:19:31 +0000205 }
John McCall16927f62010-03-12 01:19:31 +0000206 }
207
208 // That's it, give up.
John McCallfb803d72010-03-17 04:58:56 +0000209 return OnFailure;
John McCall5b0829a2010-02-10 09:31:12 +0000210}
211
212/// Finds the best path from the naming class to the declaring class,
213/// taking friend declarations into account.
214///
John McCalla332b952010-03-18 23:49:19 +0000215/// \param FinalAccess the access of the "final step", or AS_none if
216/// there is no final step.
John McCall5b0829a2010-02-10 09:31:12 +0000217/// \return null if friendship is dependent
218static CXXBasePath *FindBestPath(Sema &S,
219 const EffectiveContext &EC,
220 CXXRecordDecl *Derived,
221 CXXRecordDecl *Base,
John McCalla332b952010-03-18 23:49:19 +0000222 AccessSpecifier FinalAccess,
John McCall5b0829a2010-02-10 09:31:12 +0000223 CXXBasePaths &Paths) {
224 // Derive the paths to the desired base.
225 bool isDerived = Derived->isDerivedFrom(Base, Paths);
226 assert(isDerived && "derived class not actually derived from base");
227 (void) isDerived;
228
229 CXXBasePath *BestPath = 0;
230
John McCalla332b952010-03-18 23:49:19 +0000231 assert(FinalAccess != AS_none && "forbidden access after declaring class");
232
John McCall5b0829a2010-02-10 09:31:12 +0000233 // Derive the friend-modified access along each path.
234 for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
235 PI != PE; ++PI) {
236
237 // Walk through the path backwards.
John McCalla332b952010-03-18 23:49:19 +0000238 AccessSpecifier PathAccess = FinalAccess;
John McCall5b0829a2010-02-10 09:31:12 +0000239 CXXBasePath::iterator I = PI->end(), E = PI->begin();
240 while (I != E) {
241 --I;
242
John McCalla332b952010-03-18 23:49:19 +0000243 assert(PathAccess != AS_none);
244
245 // If the declaration is a private member of a base class, there
246 // is no level of friendship in derived classes that can make it
247 // accessible.
248 if (PathAccess == AS_private) {
249 PathAccess = AS_none;
250 break;
251 }
252
John McCall5b0829a2010-02-10 09:31:12 +0000253 AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
254 if (BaseAccess != AS_public) {
255 switch (GetFriendKind(S, EC, I->Class)) {
John McCalla332b952010-03-18 23:49:19 +0000256 case Sema::AR_inaccessible:
257 PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess);
258 break;
259 case Sema::AR_accessible:
260 PathAccess = AS_public;
261 break;
262 case Sema::AR_dependent:
263 return 0;
John McCall5b0829a2010-02-10 09:31:12 +0000264 case Sema::AR_delayed:
265 llvm_unreachable("friend resolution is never delayed"); break;
266 }
267 }
John McCall5b0829a2010-02-10 09:31:12 +0000268 }
269
270 // Note that we modify the path's Access field to the
271 // friend-modified access.
272 if (BestPath == 0 || PathAccess < BestPath->Access) {
273 BestPath = &*PI;
274 BestPath->Access = PathAccess;
275 }
276 }
277
278 return BestPath;
279}
280
281/// Diagnose the path which caused the given declaration or base class
282/// to become inaccessible.
283static void DiagnoseAccessPath(Sema &S,
284 const EffectiveContext &EC,
285 CXXRecordDecl *NamingClass,
286 CXXRecordDecl *DeclaringClass,
287 NamedDecl *D, AccessSpecifier Access) {
John McCall553c0792010-01-23 00:46:32 +0000288 // Easy case: the decl's natural access determined its path access.
John McCall5b0829a2010-02-10 09:31:12 +0000289 // We have to check against AS_private here in case Access is AS_none,
290 // indicating a non-public member of a private base class.
291 //
292 // DependentFriend should be impossible here.
293 if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
294 switch (GetFriendKind(S, EC, DeclaringClass)) {
295 case Sema::AR_inaccessible: {
296 S.Diag(D->getLocation(), diag::note_access_natural)
297 << (unsigned) (Access == AS_protected)
298 << /*FIXME: not implicitly*/ 0;
299 return;
300 }
301
302 case Sema::AR_accessible: break;
303
304 case Sema::AR_dependent:
305 case Sema::AR_delayed:
306 llvm_unreachable("dependent/delayed not allowed");
307 return;
308 }
309 }
310
311 CXXBasePaths Paths;
John McCalla332b952010-03-18 23:49:19 +0000312 CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass,
313 AS_public, Paths);
John McCall5b0829a2010-02-10 09:31:12 +0000314
315 CXXBasePath::iterator I = Path.end(), E = Path.begin();
316 while (I != E) {
317 --I;
318
319 const CXXBaseSpecifier *BS = I->Base;
320 AccessSpecifier BaseAccess = BS->getAccessSpecifier();
321
322 // If this is public inheritance, or the derived class is a friend,
323 // skip this step.
324 if (BaseAccess == AS_public)
325 continue;
326
327 switch (GetFriendKind(S, EC, I->Class)) {
328 case Sema::AR_accessible: continue;
329 case Sema::AR_inaccessible: break;
330
331 case Sema::AR_dependent:
332 case Sema::AR_delayed:
333 llvm_unreachable("dependent friendship, should not be diagnosing");
334 }
335
336 // Check whether this base specifier is the tighest point
337 // constraining access. We have to check against AS_private for
338 // the same reasons as above.
339 if (BaseAccess == AS_private || BaseAccess >= Access) {
340
341 // We're constrained by inheritance, but we want to say
342 // "declared private here" if we're diagnosing a hierarchy
343 // conversion and this is the final step.
344 unsigned diagnostic;
345 if (D) diagnostic = diag::note_access_constrained_by_path;
346 else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural;
347 else diagnostic = diag::note_access_constrained_by_path;
348
349 S.Diag(BS->getSourceRange().getBegin(), diagnostic)
350 << BS->getSourceRange()
351 << (BaseAccess == AS_protected)
352 << (BS->getAccessSpecifierAsWritten() == AS_none);
353 return;
354 }
355 }
356
357 llvm_unreachable("access not apparently constrained by path");
358}
359
360/// Diagnose an inaccessible class member.
361static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc,
362 const EffectiveContext &EC,
363 CXXRecordDecl *NamingClass,
364 AccessSpecifier Access,
365 const Sema::AccessedEntity &Entity) {
366 NamedDecl *D = Entity.getTargetDecl();
367 CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
368
John McCall1064d7e2010-03-16 05:22:47 +0000369 S.Diag(Loc, Entity.getDiag())
370 << (Access == AS_protected)
371 << D->getDeclName()
372 << S.Context.getTypeDeclType(NamingClass)
373 << S.Context.getTypeDeclType(DeclaringClass);
John McCall5b0829a2010-02-10 09:31:12 +0000374 DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
375}
376
377/// Diagnose an inaccessible hierarchy conversion.
378static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc,
379 const EffectiveContext &EC,
380 AccessSpecifier Access,
John McCall1064d7e2010-03-16 05:22:47 +0000381 const Sema::AccessedEntity &Entity) {
382 S.Diag(Loc, Entity.getDiag())
383 << (Access == AS_protected)
384 << DeclarationName()
385 << S.Context.getTypeDeclType(Entity.getDerivedClass())
386 << S.Context.getTypeDeclType(Entity.getBaseClass());
John McCall5b0829a2010-02-10 09:31:12 +0000387 DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
388 Entity.getBaseClass(), 0, Access);
389}
390
John McCall1064d7e2010-03-16 05:22:47 +0000391static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
John McCall5b0829a2010-02-10 09:31:12 +0000392 const EffectiveContext &EC,
393 CXXRecordDecl *NamingClass,
394 AccessSpecifier Access,
John McCall1064d7e2010-03-16 05:22:47 +0000395 const Sema::AccessedEntity &Entity) {
John McCall5b0829a2010-02-10 09:31:12 +0000396 if (Entity.isMemberAccess())
397 DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
398 else
John McCall1064d7e2010-03-16 05:22:47 +0000399 DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity);
John McCall5b0829a2010-02-10 09:31:12 +0000400}
401
402
403/// Try to elevate access using friend declarations. This is
404/// potentially quite expensive.
405static void TryElevateAccess(Sema &S,
406 const EffectiveContext &EC,
407 const Sema::AccessedEntity &Entity,
408 AccessSpecifier &Access) {
409 CXXRecordDecl *DeclaringClass;
410 if (Entity.isMemberAccess()) {
411 DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
412 } else {
413 DeclaringClass = Entity.getBaseClass();
414 }
415 CXXRecordDecl *NamingClass = Entity.getNamingClass();
416
417 // Adjust the declaration of the referred entity.
John McCalla332b952010-03-18 23:49:19 +0000418 AccessSpecifier DeclAccess = AS_public;
John McCall5b0829a2010-02-10 09:31:12 +0000419 if (Entity.isMemberAccess()) {
420 NamedDecl *Target = Entity.getTargetDecl();
421
422 DeclAccess = Target->getAccess();
423 if (DeclAccess != AS_public) {
424 switch (GetFriendKind(S, EC, DeclaringClass)) {
425 case Sema::AR_accessible: DeclAccess = AS_public; break;
426 case Sema::AR_inaccessible: break;
427 case Sema::AR_dependent: /* FIXME: delay dependent friendship */ return;
428 case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
429 }
430 }
431
432 if (DeclaringClass == NamingClass) {
433 Access = DeclAccess;
434 return;
435 }
436 }
437
438 assert(DeclaringClass != NamingClass);
439
440 // Append the declaration's access if applicable.
441 CXXBasePaths Paths;
442 CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(),
John McCalla332b952010-03-18 23:49:19 +0000443 DeclaringClass, DeclAccess, Paths);
John McCall5b0829a2010-02-10 09:31:12 +0000444 if (!Path) {
445 // FIXME: delay dependent friendship
John McCall553c0792010-01-23 00:46:32 +0000446 return;
447 }
448
John McCalla332b952010-03-18 23:49:19 +0000449 // Grab the access along the best path (note that this includes the
450 // final-step access).
John McCall5b0829a2010-02-10 09:31:12 +0000451 AccessSpecifier NewAccess = Path->Access;
John McCall5b0829a2010-02-10 09:31:12 +0000452 assert(NewAccess <= Access && "access along best path worse than direct?");
453 Access = NewAccess;
John McCall553c0792010-01-23 00:46:32 +0000454}
455
John McCall5b0829a2010-02-10 09:31:12 +0000456/// Checks access to an entity from the given effective context.
457static Sema::AccessResult CheckEffectiveAccess(Sema &S,
458 const EffectiveContext &EC,
459 SourceLocation Loc,
John McCall1064d7e2010-03-16 05:22:47 +0000460 Sema::AccessedEntity const &Entity) {
John McCall5b0829a2010-02-10 09:31:12 +0000461 AccessSpecifier Access = Entity.getAccess();
John McCallfb803d72010-03-17 04:58:56 +0000462 assert(Access != AS_public && "called for public access!");
John McCall553c0792010-01-23 00:46:32 +0000463
John McCallfb803d72010-03-17 04:58:56 +0000464 // Find a non-anonymous naming class. For records with access,
465 // there should always be one of these.
John McCall5b0829a2010-02-10 09:31:12 +0000466 CXXRecordDecl *NamingClass = Entity.getNamingClass();
John McCall553c0792010-01-23 00:46:32 +0000467 while (NamingClass->isAnonymousStructOrUnion())
John McCall1064d7e2010-03-16 05:22:47 +0000468 NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
John McCall553c0792010-01-23 00:46:32 +0000469
John McCallfb803d72010-03-17 04:58:56 +0000470 // White-list accesses from classes with privileges equivalent to the
471 // naming class --- but only if the access path isn't forbidden
472 // (i.e. an access of a private member from a subclass).
473 if (Access != AS_none && EC.includesClass(NamingClass))
John McCall5b0829a2010-02-10 09:31:12 +0000474 return Sema::AR_accessible;
John McCallfb803d72010-03-17 04:58:56 +0000475
476 // Try to elevate access.
477 // FIXME: delay if elevation was dependent?
478 // TODO: on some code, it might be better to do the protected check
479 // without trying to elevate first.
480 TryElevateAccess(S, EC, Entity, Access);
481 if (Access == AS_public) return Sema::AR_accessible;
John McCall553c0792010-01-23 00:46:32 +0000482
483 // Protected access.
484 if (Access == AS_protected) {
485 // FIXME: implement [class.protected]p1
John McCallfb803d72010-03-17 04:58:56 +0000486 for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
487 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I)
488 if ((*I)->isDerivedFrom(NamingClass))
489 return Sema::AR_accessible;
John McCall553c0792010-01-23 00:46:32 +0000490
John McCallfb803d72010-03-17 04:58:56 +0000491 // FIXME: delay if we can't decide class derivation yet.
John McCall553c0792010-01-23 00:46:32 +0000492 }
493
John McCall5b0829a2010-02-10 09:31:12 +0000494 // Okay, that's it, reject it.
John McCall1064d7e2010-03-16 05:22:47 +0000495 if (!Entity.isQuiet())
496 DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
John McCall5b0829a2010-02-10 09:31:12 +0000497 return Sema::AR_inaccessible;
498}
John McCall553c0792010-01-23 00:46:32 +0000499
John McCall5b0829a2010-02-10 09:31:12 +0000500static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
John McCall1064d7e2010-03-16 05:22:47 +0000501 const Sema::AccessedEntity &Entity) {
John McCall5b0829a2010-02-10 09:31:12 +0000502 // If the access path is public, it's accessible everywhere.
503 if (Entity.getAccess() == AS_public)
504 return Sema::AR_accessible;
John McCall553c0792010-01-23 00:46:32 +0000505
John McCall5b0829a2010-02-10 09:31:12 +0000506 // If we're currently parsing a top-level declaration, delay
507 // diagnostics. This is the only case where parsing a declaration
508 // can actually change our effective context for the purposes of
509 // access control.
510 if (S.CurContext->isFileContext() && S.ParsingDeclDepth) {
John McCall5b0829a2010-02-10 09:31:12 +0000511 S.DelayedDiagnostics.push_back(
512 Sema::DelayedDiagnostic::makeAccess(Loc, Entity));
513 return Sema::AR_delayed;
John McCall553c0792010-01-23 00:46:32 +0000514 }
515
John McCall5b0829a2010-02-10 09:31:12 +0000516 return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
John McCall1064d7e2010-03-16 05:22:47 +0000517 Loc, Entity);
John McCall553c0792010-01-23 00:46:32 +0000518}
519
John McCall86121512010-01-27 03:50:35 +0000520void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
John McCall86121512010-01-27 03:50:35 +0000521 // Pretend we did this from the context of the newly-parsed
522 // declaration.
John McCall5b0829a2010-02-10 09:31:12 +0000523 EffectiveContext EC(Ctx->getDeclContext());
John McCall86121512010-01-27 03:50:35 +0000524
John McCall1064d7e2010-03-16 05:22:47 +0000525 if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData()))
John McCall86121512010-01-27 03:50:35 +0000526 DD.Triggered = true;
527}
528
John McCall5b0829a2010-02-10 09:31:12 +0000529Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
John McCalla0296f72010-03-19 07:35:19 +0000530 DeclAccessPair Found) {
John McCall1064d7e2010-03-16 05:22:47 +0000531 if (!getLangOptions().AccessControl ||
532 !E->getNamingClass() ||
John McCalla0296f72010-03-19 07:35:19 +0000533 Found.getAccess() == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000534 return AR_accessible;
John McCall58cc69d2010-01-27 01:50:18 +0000535
John McCalla0296f72010-03-19 07:35:19 +0000536 AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found);
John McCall1064d7e2010-03-16 05:22:47 +0000537 Entity.setDiag(diag::err_access) << E->getSourceRange();
538
539 return CheckAccess(*this, E->getNameLoc(), Entity);
John McCall58cc69d2010-01-27 01:50:18 +0000540}
541
542/// Perform access-control checking on a previously-unresolved member
543/// access which has now been resolved to a member.
John McCall5b0829a2010-02-10 09:31:12 +0000544Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
John McCalla0296f72010-03-19 07:35:19 +0000545 DeclAccessPair Found) {
John McCall1064d7e2010-03-16 05:22:47 +0000546 if (!getLangOptions().AccessControl ||
John McCalla0296f72010-03-19 07:35:19 +0000547 Found.getAccess() == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000548 return AR_accessible;
John McCall58cc69d2010-01-27 01:50:18 +0000549
John McCalla0296f72010-03-19 07:35:19 +0000550 AccessedEntity Entity(AccessedEntity::Member, E->getNamingClass(), Found);
John McCall1064d7e2010-03-16 05:22:47 +0000551 Entity.setDiag(diag::err_access) << E->getSourceRange();
552
553 return CheckAccess(*this, E->getMemberLoc(), Entity);
John McCall58cc69d2010-01-27 01:50:18 +0000554}
555
John McCall5b0829a2010-02-10 09:31:12 +0000556Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
John McCall1064d7e2010-03-16 05:22:47 +0000557 CXXDestructorDecl *Dtor,
558 const PartialDiagnostic &PDiag) {
John McCall6781b052010-02-02 08:45:54 +0000559 if (!getLangOptions().AccessControl)
John McCall5b0829a2010-02-10 09:31:12 +0000560 return AR_accessible;
John McCall6781b052010-02-02 08:45:54 +0000561
John McCall1064d7e2010-03-16 05:22:47 +0000562 // There's never a path involved when checking implicit destructor access.
John McCall6781b052010-02-02 08:45:54 +0000563 AccessSpecifier Access = Dtor->getAccess();
564 if (Access == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000565 return AR_accessible;
John McCall6781b052010-02-02 08:45:54 +0000566
John McCall1064d7e2010-03-16 05:22:47 +0000567 CXXRecordDecl *NamingClass = Dtor->getParent();
John McCalla0296f72010-03-19 07:35:19 +0000568 AccessedEntity Entity(AccessedEntity::Member, NamingClass,
569 DeclAccessPair::make(Dtor, Access));
John McCall1064d7e2010-03-16 05:22:47 +0000570 Entity.setDiag(PDiag); // TODO: avoid copy
571
572 return CheckAccess(*this, Loc, Entity);
John McCall6781b052010-02-02 08:45:54 +0000573}
574
John McCall760af172010-02-01 03:16:54 +0000575/// Checks access to a constructor.
John McCall5b0829a2010-02-10 09:31:12 +0000576Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
John McCall760af172010-02-01 03:16:54 +0000577 CXXConstructorDecl *Constructor,
578 AccessSpecifier Access) {
John McCall1064d7e2010-03-16 05:22:47 +0000579 if (!getLangOptions().AccessControl ||
580 Access == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000581 return AR_accessible;
John McCall760af172010-02-01 03:16:54 +0000582
John McCall5b0829a2010-02-10 09:31:12 +0000583 CXXRecordDecl *NamingClass = Constructor->getParent();
John McCalla0296f72010-03-19 07:35:19 +0000584 AccessedEntity Entity(AccessedEntity::Member, NamingClass,
585 DeclAccessPair::make(Constructor, Access));
John McCall1064d7e2010-03-16 05:22:47 +0000586 Entity.setDiag(diag::err_access_ctor);
587
588 return CheckAccess(*this, UseLoc, Entity);
John McCall760af172010-02-01 03:16:54 +0000589}
590
John McCallab8c2732010-03-16 06:11:48 +0000591/// Checks direct (i.e. non-inherited) access to an arbitrary class
592/// member.
593Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
594 NamedDecl *Target,
595 const PartialDiagnostic &Diag) {
596 AccessSpecifier Access = Target->getAccess();
597 if (!getLangOptions().AccessControl ||
598 Access == AS_public)
599 return AR_accessible;
600
601 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext());
John McCalla0296f72010-03-19 07:35:19 +0000602 AccessedEntity Entity(AccessedEntity::Member, NamingClass,
603 DeclAccessPair::make(Target, Access));
John McCallab8c2732010-03-16 06:11:48 +0000604 Entity.setDiag(Diag);
605 return CheckAccess(*this, UseLoc, Entity);
606}
607
608
John McCallfb6f5262010-03-18 08:19:33 +0000609/// Checks access to an overloaded operator new or delete.
610Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc,
611 SourceRange PlacementRange,
612 CXXRecordDecl *NamingClass,
John McCalla0296f72010-03-19 07:35:19 +0000613 DeclAccessPair Found) {
John McCallfb6f5262010-03-18 08:19:33 +0000614 if (!getLangOptions().AccessControl ||
615 !NamingClass ||
John McCalla0296f72010-03-19 07:35:19 +0000616 Found.getAccess() == AS_public)
John McCallfb6f5262010-03-18 08:19:33 +0000617 return AR_accessible;
618
John McCalla0296f72010-03-19 07:35:19 +0000619 AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found);
John McCallfb6f5262010-03-18 08:19:33 +0000620 Entity.setDiag(diag::err_access)
621 << PlacementRange;
622
623 return CheckAccess(*this, OpLoc, Entity);
624}
625
John McCall760af172010-02-01 03:16:54 +0000626/// Checks access to an overloaded member operator, including
627/// conversion operators.
John McCall5b0829a2010-02-10 09:31:12 +0000628Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
629 Expr *ObjectExpr,
John McCall1064d7e2010-03-16 05:22:47 +0000630 Expr *ArgExpr,
John McCalla0296f72010-03-19 07:35:19 +0000631 DeclAccessPair Found) {
John McCall1064d7e2010-03-16 05:22:47 +0000632 if (!getLangOptions().AccessControl ||
John McCalla0296f72010-03-19 07:35:19 +0000633 Found.getAccess() == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000634 return AR_accessible;
John McCallb3a44002010-01-28 01:42:12 +0000635
636 const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
637 assert(RT && "found member operator but object expr not of record type");
638 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
639
John McCalla0296f72010-03-19 07:35:19 +0000640 AccessedEntity Entity(AccessedEntity::Member, NamingClass, Found);
John McCall1064d7e2010-03-16 05:22:47 +0000641 Entity.setDiag(diag::err_access)
642 << ObjectExpr->getSourceRange()
643 << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
644
645 return CheckAccess(*this, OpLoc, Entity);
John McCall5b0829a2010-02-10 09:31:12 +0000646}
John McCallb3a44002010-01-28 01:42:12 +0000647
John McCall5b0829a2010-02-10 09:31:12 +0000648/// Checks access for a hierarchy conversion.
649///
650/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
651/// or a derived-to-base conversion (false)
652/// \param ForceCheck true if this check should be performed even if access
653/// control is disabled; some things rely on this for semantics
654/// \param ForceUnprivileged true if this check should proceed as if the
655/// context had no special privileges
656/// \param ADK controls the kind of diagnostics that are used
657Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
John McCall5b0829a2010-02-10 09:31:12 +0000658 QualType Base,
659 QualType Derived,
660 const CXXBasePath &Path,
John McCall1064d7e2010-03-16 05:22:47 +0000661 unsigned DiagID,
John McCall5b0829a2010-02-10 09:31:12 +0000662 bool ForceCheck,
John McCall1064d7e2010-03-16 05:22:47 +0000663 bool ForceUnprivileged) {
John McCall5b0829a2010-02-10 09:31:12 +0000664 if (!ForceCheck && !getLangOptions().AccessControl)
665 return AR_accessible;
John McCallb3a44002010-01-28 01:42:12 +0000666
John McCall5b0829a2010-02-10 09:31:12 +0000667 if (Path.Access == AS_public)
668 return AR_accessible;
John McCallb3a44002010-01-28 01:42:12 +0000669
John McCall5b0829a2010-02-10 09:31:12 +0000670 CXXRecordDecl *BaseD, *DerivedD;
671 BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
672 DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
John McCall1064d7e2010-03-16 05:22:47 +0000673
674 AccessedEntity Entity(AccessedEntity::Base, BaseD, DerivedD, Path.Access);
675 if (DiagID)
676 Entity.setDiag(DiagID) << Derived << Base;
John McCall5b0829a2010-02-10 09:31:12 +0000677
678 if (ForceUnprivileged)
John McCall1064d7e2010-03-16 05:22:47 +0000679 return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity);
680 return CheckAccess(*this, AccessLoc, Entity);
John McCallb3a44002010-01-28 01:42:12 +0000681}
682
John McCall553c0792010-01-23 00:46:32 +0000683/// Checks access to all the declarations in the given result set.
John McCall5b0829a2010-02-10 09:31:12 +0000684void Sema::CheckLookupAccess(const LookupResult &R) {
685 assert(getLangOptions().AccessControl
686 && "performing access check without access control");
687 assert(R.getNamingClass() && "performing access check without naming class");
688
John McCall1064d7e2010-03-16 05:22:47 +0000689 for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
690 if (I.getAccess() != AS_public) {
691 AccessedEntity Entity(AccessedEntity::Member,
John McCalla0296f72010-03-19 07:35:19 +0000692 R.getNamingClass(),
693 I.getPair());
John McCall1064d7e2010-03-16 05:22:47 +0000694 Entity.setDiag(diag::err_access);
695
696 CheckAccess(*this, R.getNameLoc(), Entity);
697 }
698 }
John McCall553c0792010-01-23 00:46:32 +0000699}