blob: f0a38d5970ccd2d6e34b24beb35fde0f7f2889b9 [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 McCallc373d482010-01-27 01:50:18 +000020#include "clang/AST/ExprCXX.h"
21
Anders Carlssonc60e8882009-03-27 04:54:36 +000022using namespace clang;
23
Anders Carlsson29f006b2009-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 Stump1eb44332009-09-09 15:08:12 +000027bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl,
Anders Carlssonc60e8882009-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 Stump1eb44332009-09-09 15:08:12 +000035
Anders Carlssonc60e8882009-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 Stump1eb44332009-09-09 15:08:12 +000039 Diag(MemberDecl->getLocation(),
40 diag::err_class_redeclared_with_different_access)
Anders Carlssonc60e8882009-03-27 04:54:36 +000041 << MemberDecl << LexicalAS;
42 Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration)
43 << PrevMemberDecl << PrevMemberDecl->getAccess();
John McCall44e067b2009-12-23 00:37:40 +000044
45 MemberDecl->setAccess(LexicalAS);
Anders Carlssonc60e8882009-03-27 04:54:36 +000046 return true;
47 }
Mike Stump1eb44332009-09-09 15:08:12 +000048
Anders Carlssonc60e8882009-03-27 04:54:36 +000049 MemberDecl->setAccess(PrevMemberDecl->getAccess());
50 return false;
51}
Anders Carlsson29f006b2009-03-27 05:05:05 +000052
John McCall6b2accb2010-02-10 09:31:12 +000053namespace {
54struct EffectiveContext {
55 EffectiveContext() : Record(0), Function(0) {}
Anders Carlssonc4f1e872009-03-27 06:03:27 +000056
John McCall6b2accb2010-02-10 09:31:12 +000057 explicit EffectiveContext(DeclContext *DC) {
58 if (isa<FunctionDecl>(DC)) {
John McCalld60e22e2010-03-12 01:19:31 +000059 Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
John McCall6b2accb2010-02-10 09:31:12 +000060 DC = Function->getDeclContext();
61 } else
62 Function = 0;
63
64 if (isa<CXXRecordDecl>(DC))
65 Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
Anders Carlssonc4f1e872009-03-27 06:03:27 +000066 else
John McCall6b2accb2010-02-10 09:31:12 +000067 Record = 0;
Anders Carlssonc4f1e872009-03-27 06:03:27 +000068 }
Sebastian Redl726212f2009-07-18 14:32:15 +000069
John McCall6b2accb2010-02-10 09:31:12 +000070 bool isClass(const CXXRecordDecl *R) const {
71 return R->getCanonicalDecl() == Record;
72 }
73
74 CXXRecordDecl *Record;
75 FunctionDecl *Function;
76};
Anders Carlsson29f006b2009-03-27 05:05:05 +000077}
John McCall92f88312010-01-23 00:46:32 +000078
John McCall6b2accb2010-02-10 09:31:12 +000079static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) {
80 CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
81 while (DeclaringClass->isAnonymousStructOrUnion())
82 DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext());
83 return DeclaringClass;
84}
85
86static Sema::AccessResult GetFriendKind(Sema &S,
87 const EffectiveContext &EC,
88 const CXXRecordDecl *Class) {
John McCalld60e22e2010-03-12 01:19:31 +000089 // A class always has access to its own members.
John McCall6b2accb2010-02-10 09:31:12 +000090 if (EC.isClass(Class))
91 return Sema::AR_accessible;
92
John McCalld60e22e2010-03-12 01:19:31 +000093 // Okay, check friends.
94 for (CXXRecordDecl::friend_iterator I = Class->friend_begin(),
95 E = Class->friend_end(); I != E; ++I) {
96 FriendDecl *Friend = *I;
97
98 if (Type *T = Friend->getFriendType()) {
99 if (EC.Record &&
100 S.Context.hasSameType(QualType(T, 0),
101 S.Context.getTypeDeclType(EC.Record)))
102 return Sema::AR_accessible;
103 } else {
104 NamedDecl *D
105 = cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl());
106
107 // The decl pointers in EC have been canonicalized, so pointer
108 // equality is sufficient.
109 if (D == EC.Function || D == EC.Record)
110 return Sema::AR_accessible;
111 }
112
113 // FIXME: templates! templated contexts! dependent delay!
114 }
115
116 // That's it, give up.
John McCall6b2accb2010-02-10 09:31:12 +0000117 return Sema::AR_inaccessible;
118}
119
120/// Finds the best path from the naming class to the declaring class,
121/// taking friend declarations into account.
122///
123/// \return null if friendship is dependent
124static CXXBasePath *FindBestPath(Sema &S,
125 const EffectiveContext &EC,
126 CXXRecordDecl *Derived,
127 CXXRecordDecl *Base,
128 CXXBasePaths &Paths) {
129 // Derive the paths to the desired base.
130 bool isDerived = Derived->isDerivedFrom(Base, Paths);
131 assert(isDerived && "derived class not actually derived from base");
132 (void) isDerived;
133
134 CXXBasePath *BestPath = 0;
135
136 // Derive the friend-modified access along each path.
137 for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
138 PI != PE; ++PI) {
139
140 // Walk through the path backwards.
141 AccessSpecifier PathAccess = AS_public;
142 CXXBasePath::iterator I = PI->end(), E = PI->begin();
143 while (I != E) {
144 --I;
145
146 AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
147 if (BaseAccess != AS_public) {
148 switch (GetFriendKind(S, EC, I->Class)) {
149 case Sema::AR_inaccessible: break;
150 case Sema::AR_accessible: BaseAccess = AS_public; break;
151 case Sema::AR_dependent: return 0;
152 case Sema::AR_delayed:
153 llvm_unreachable("friend resolution is never delayed"); break;
154 }
155 }
156
157 PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess);
158 }
159
160 // Note that we modify the path's Access field to the
161 // friend-modified access.
162 if (BestPath == 0 || PathAccess < BestPath->Access) {
163 BestPath = &*PI;
164 BestPath->Access = PathAccess;
165 }
166 }
167
168 return BestPath;
169}
170
171/// Diagnose the path which caused the given declaration or base class
172/// to become inaccessible.
173static void DiagnoseAccessPath(Sema &S,
174 const EffectiveContext &EC,
175 CXXRecordDecl *NamingClass,
176 CXXRecordDecl *DeclaringClass,
177 NamedDecl *D, AccessSpecifier Access) {
John McCall92f88312010-01-23 00:46:32 +0000178 // Easy case: the decl's natural access determined its path access.
John McCall6b2accb2010-02-10 09:31:12 +0000179 // We have to check against AS_private here in case Access is AS_none,
180 // indicating a non-public member of a private base class.
181 //
182 // DependentFriend should be impossible here.
183 if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
184 switch (GetFriendKind(S, EC, DeclaringClass)) {
185 case Sema::AR_inaccessible: {
186 S.Diag(D->getLocation(), diag::note_access_natural)
187 << (unsigned) (Access == AS_protected)
188 << /*FIXME: not implicitly*/ 0;
189 return;
190 }
191
192 case Sema::AR_accessible: break;
193
194 case Sema::AR_dependent:
195 case Sema::AR_delayed:
196 llvm_unreachable("dependent/delayed not allowed");
197 return;
198 }
199 }
200
201 CXXBasePaths Paths;
202 CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, Paths);
203
204 CXXBasePath::iterator I = Path.end(), E = Path.begin();
205 while (I != E) {
206 --I;
207
208 const CXXBaseSpecifier *BS = I->Base;
209 AccessSpecifier BaseAccess = BS->getAccessSpecifier();
210
211 // If this is public inheritance, or the derived class is a friend,
212 // skip this step.
213 if (BaseAccess == AS_public)
214 continue;
215
216 switch (GetFriendKind(S, EC, I->Class)) {
217 case Sema::AR_accessible: continue;
218 case Sema::AR_inaccessible: break;
219
220 case Sema::AR_dependent:
221 case Sema::AR_delayed:
222 llvm_unreachable("dependent friendship, should not be diagnosing");
223 }
224
225 // Check whether this base specifier is the tighest point
226 // constraining access. We have to check against AS_private for
227 // the same reasons as above.
228 if (BaseAccess == AS_private || BaseAccess >= Access) {
229
230 // We're constrained by inheritance, but we want to say
231 // "declared private here" if we're diagnosing a hierarchy
232 // conversion and this is the final step.
233 unsigned diagnostic;
234 if (D) diagnostic = diag::note_access_constrained_by_path;
235 else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural;
236 else diagnostic = diag::note_access_constrained_by_path;
237
238 S.Diag(BS->getSourceRange().getBegin(), diagnostic)
239 << BS->getSourceRange()
240 << (BaseAccess == AS_protected)
241 << (BS->getAccessSpecifierAsWritten() == AS_none);
242 return;
243 }
244 }
245
246 llvm_unreachable("access not apparently constrained by path");
247}
248
249/// Diagnose an inaccessible class member.
250static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc,
251 const EffectiveContext &EC,
252 CXXRecordDecl *NamingClass,
253 AccessSpecifier Access,
254 const Sema::AccessedEntity &Entity) {
255 NamedDecl *D = Entity.getTargetDecl();
256 CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
257
John McCall58e6f342010-03-16 05:22:47 +0000258 S.Diag(Loc, Entity.getDiag())
259 << (Access == AS_protected)
260 << D->getDeclName()
261 << S.Context.getTypeDeclType(NamingClass)
262 << S.Context.getTypeDeclType(DeclaringClass);
John McCall6b2accb2010-02-10 09:31:12 +0000263 DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
264}
265
266/// Diagnose an inaccessible hierarchy conversion.
267static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc,
268 const EffectiveContext &EC,
269 AccessSpecifier Access,
John McCall58e6f342010-03-16 05:22:47 +0000270 const Sema::AccessedEntity &Entity) {
271 S.Diag(Loc, Entity.getDiag())
272 << (Access == AS_protected)
273 << DeclarationName()
274 << S.Context.getTypeDeclType(Entity.getDerivedClass())
275 << S.Context.getTypeDeclType(Entity.getBaseClass());
John McCall6b2accb2010-02-10 09:31:12 +0000276 DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
277 Entity.getBaseClass(), 0, Access);
278}
279
John McCall58e6f342010-03-16 05:22:47 +0000280static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
John McCall6b2accb2010-02-10 09:31:12 +0000281 const EffectiveContext &EC,
282 CXXRecordDecl *NamingClass,
283 AccessSpecifier Access,
John McCall58e6f342010-03-16 05:22:47 +0000284 const Sema::AccessedEntity &Entity) {
John McCall6b2accb2010-02-10 09:31:12 +0000285 if (Entity.isMemberAccess())
286 DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
287 else
John McCall58e6f342010-03-16 05:22:47 +0000288 DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity);
John McCall6b2accb2010-02-10 09:31:12 +0000289}
290
291
292/// Try to elevate access using friend declarations. This is
293/// potentially quite expensive.
294static void TryElevateAccess(Sema &S,
295 const EffectiveContext &EC,
296 const Sema::AccessedEntity &Entity,
297 AccessSpecifier &Access) {
298 CXXRecordDecl *DeclaringClass;
299 if (Entity.isMemberAccess()) {
300 DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
301 } else {
302 DeclaringClass = Entity.getBaseClass();
303 }
304 CXXRecordDecl *NamingClass = Entity.getNamingClass();
305
306 // Adjust the declaration of the referred entity.
307 AccessSpecifier DeclAccess = AS_none;
308 if (Entity.isMemberAccess()) {
309 NamedDecl *Target = Entity.getTargetDecl();
310
311 DeclAccess = Target->getAccess();
312 if (DeclAccess != AS_public) {
313 switch (GetFriendKind(S, EC, DeclaringClass)) {
314 case Sema::AR_accessible: DeclAccess = AS_public; break;
315 case Sema::AR_inaccessible: break;
316 case Sema::AR_dependent: /* FIXME: delay dependent friendship */ return;
317 case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
318 }
319 }
320
321 if (DeclaringClass == NamingClass) {
322 Access = DeclAccess;
323 return;
324 }
325 }
326
327 assert(DeclaringClass != NamingClass);
328
329 // Append the declaration's access if applicable.
330 CXXBasePaths Paths;
331 CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(),
332 DeclaringClass, Paths);
333 if (!Path) {
334 // FIXME: delay dependent friendship
John McCall92f88312010-01-23 00:46:32 +0000335 return;
336 }
337
John McCall6b2accb2010-02-10 09:31:12 +0000338 // Grab the access along the best path.
339 AccessSpecifier NewAccess = Path->Access;
340 if (Entity.isMemberAccess())
341 NewAccess = CXXRecordDecl::MergeAccess(NewAccess, DeclAccess);
342
343 assert(NewAccess <= Access && "access along best path worse than direct?");
344 Access = NewAccess;
John McCall92f88312010-01-23 00:46:32 +0000345}
346
John McCall6b2accb2010-02-10 09:31:12 +0000347/// Checks access to an entity from the given effective context.
348static Sema::AccessResult CheckEffectiveAccess(Sema &S,
349 const EffectiveContext &EC,
350 SourceLocation Loc,
John McCall58e6f342010-03-16 05:22:47 +0000351 Sema::AccessedEntity const &Entity) {
John McCall6b2accb2010-02-10 09:31:12 +0000352 AccessSpecifier Access = Entity.getAccess();
353 assert(Access != AS_public);
John McCall92f88312010-01-23 00:46:32 +0000354
John McCall6b2accb2010-02-10 09:31:12 +0000355 CXXRecordDecl *NamingClass = Entity.getNamingClass();
John McCall92f88312010-01-23 00:46:32 +0000356 while (NamingClass->isAnonymousStructOrUnion())
357 // This should be guaranteed by the fact that the decl has
358 // non-public access. If not, we should make it guaranteed!
John McCall58e6f342010-03-16 05:22:47 +0000359 NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
John McCall92f88312010-01-23 00:46:32 +0000360
John McCall6b2accb2010-02-10 09:31:12 +0000361 if (!EC.Record) {
362 TryElevateAccess(S, EC, Entity, Access);
363 if (Access == AS_public) return Sema::AR_accessible;
364
John McCall58e6f342010-03-16 05:22:47 +0000365 if (!Entity.isQuiet())
366 DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
John McCall6b2accb2010-02-10 09:31:12 +0000367 return Sema::AR_inaccessible;
368 }
369
John McCall92f88312010-01-23 00:46:32 +0000370 // White-list accesses from within the declaring class.
John McCall6b2accb2010-02-10 09:31:12 +0000371 if (Access != AS_none && EC.isClass(NamingClass))
372 return Sema::AR_accessible;
373
374 // If the access is worse than 'protected', try to promote to it using
375 // friend declarations.
376 bool TriedElevation = false;
377 if (Access != AS_protected) {
378 TryElevateAccess(S, EC, Entity, Access);
379 if (Access == AS_public) return Sema::AR_accessible;
380 TriedElevation = true;
381 }
John McCall92f88312010-01-23 00:46:32 +0000382
383 // Protected access.
384 if (Access == AS_protected) {
385 // FIXME: implement [class.protected]p1
John McCall6b2accb2010-02-10 09:31:12 +0000386 if (EC.Record->isDerivedFrom(NamingClass))
387 return Sema::AR_accessible;
John McCall92f88312010-01-23 00:46:32 +0000388
John McCall6b2accb2010-02-10 09:31:12 +0000389 // FIXME: delay dependent classes
John McCall92f88312010-01-23 00:46:32 +0000390 }
391
John McCall6b2accb2010-02-10 09:31:12 +0000392 // We're about to reject; one last chance to promote access.
393 if (!TriedElevation) {
394 TryElevateAccess(S, EC, Entity, Access);
395 if (Access == AS_public) return Sema::AR_accessible;
396 }
397
398 // Okay, that's it, reject it.
John McCall58e6f342010-03-16 05:22:47 +0000399 if (!Entity.isQuiet())
400 DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
John McCall6b2accb2010-02-10 09:31:12 +0000401 return Sema::AR_inaccessible;
402}
John McCall92f88312010-01-23 00:46:32 +0000403
John McCall6b2accb2010-02-10 09:31:12 +0000404static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
John McCall58e6f342010-03-16 05:22:47 +0000405 const Sema::AccessedEntity &Entity) {
John McCall6b2accb2010-02-10 09:31:12 +0000406 // If the access path is public, it's accessible everywhere.
407 if (Entity.getAccess() == AS_public)
408 return Sema::AR_accessible;
John McCall92f88312010-01-23 00:46:32 +0000409
John McCall6b2accb2010-02-10 09:31:12 +0000410 // If we're currently parsing a top-level declaration, delay
411 // diagnostics. This is the only case where parsing a declaration
412 // can actually change our effective context for the purposes of
413 // access control.
414 if (S.CurContext->isFileContext() && S.ParsingDeclDepth) {
John McCall6b2accb2010-02-10 09:31:12 +0000415 S.DelayedDiagnostics.push_back(
416 Sema::DelayedDiagnostic::makeAccess(Loc, Entity));
417 return Sema::AR_delayed;
John McCall92f88312010-01-23 00:46:32 +0000418 }
419
John McCall6b2accb2010-02-10 09:31:12 +0000420 return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
John McCall58e6f342010-03-16 05:22:47 +0000421 Loc, Entity);
John McCall92f88312010-01-23 00:46:32 +0000422}
423
John McCall2f514482010-01-27 03:50:35 +0000424void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
John McCall2f514482010-01-27 03:50:35 +0000425 // Pretend we did this from the context of the newly-parsed
426 // declaration.
John McCall6b2accb2010-02-10 09:31:12 +0000427 EffectiveContext EC(Ctx->getDeclContext());
John McCall2f514482010-01-27 03:50:35 +0000428
John McCall58e6f342010-03-16 05:22:47 +0000429 if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData()))
John McCall2f514482010-01-27 03:50:35 +0000430 DD.Triggered = true;
431}
432
John McCall6b2accb2010-02-10 09:31:12 +0000433Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
434 NamedDecl *D,
435 AccessSpecifier Access) {
John McCall58e6f342010-03-16 05:22:47 +0000436 if (!getLangOptions().AccessControl ||
437 !E->getNamingClass() ||
438 Access == AS_public)
John McCall6b2accb2010-02-10 09:31:12 +0000439 return AR_accessible;
John McCallc373d482010-01-27 01:50:18 +0000440
John McCall58e6f342010-03-16 05:22:47 +0000441 AccessedEntity Entity(AccessedEntity::Member,
442 E->getNamingClass(), Access, D);
443 Entity.setDiag(diag::err_access) << E->getSourceRange();
444
445 return CheckAccess(*this, E->getNameLoc(), Entity);
John McCallc373d482010-01-27 01:50:18 +0000446}
447
448/// Perform access-control checking on a previously-unresolved member
449/// access which has now been resolved to a member.
John McCall6b2accb2010-02-10 09:31:12 +0000450Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
451 NamedDecl *D,
452 AccessSpecifier Access) {
John McCall58e6f342010-03-16 05:22:47 +0000453 if (!getLangOptions().AccessControl ||
454 Access == AS_public)
John McCall6b2accb2010-02-10 09:31:12 +0000455 return AR_accessible;
John McCallc373d482010-01-27 01:50:18 +0000456
John McCall58e6f342010-03-16 05:22:47 +0000457 AccessedEntity Entity(AccessedEntity::Member,
458 E->getNamingClass(), Access, D);
459 Entity.setDiag(diag::err_access) << E->getSourceRange();
460
461 return CheckAccess(*this, E->getMemberLoc(), Entity);
John McCallc373d482010-01-27 01:50:18 +0000462}
463
John McCall6b2accb2010-02-10 09:31:12 +0000464Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
John McCall58e6f342010-03-16 05:22:47 +0000465 CXXDestructorDecl *Dtor,
466 const PartialDiagnostic &PDiag) {
John McCall4f9506a2010-02-02 08:45:54 +0000467 if (!getLangOptions().AccessControl)
John McCall6b2accb2010-02-10 09:31:12 +0000468 return AR_accessible;
John McCall4f9506a2010-02-02 08:45:54 +0000469
John McCall58e6f342010-03-16 05:22:47 +0000470 // There's never a path involved when checking implicit destructor access.
John McCall4f9506a2010-02-02 08:45:54 +0000471 AccessSpecifier Access = Dtor->getAccess();
472 if (Access == AS_public)
John McCall6b2accb2010-02-10 09:31:12 +0000473 return AR_accessible;
John McCall4f9506a2010-02-02 08:45:54 +0000474
John McCall58e6f342010-03-16 05:22:47 +0000475 CXXRecordDecl *NamingClass = Dtor->getParent();
476 AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Dtor);
477 Entity.setDiag(PDiag); // TODO: avoid copy
478
479 return CheckAccess(*this, Loc, Entity);
John McCall4f9506a2010-02-02 08:45:54 +0000480}
481
John McCallb13b7372010-02-01 03:16:54 +0000482/// Checks access to a constructor.
John McCall6b2accb2010-02-10 09:31:12 +0000483Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
John McCallb13b7372010-02-01 03:16:54 +0000484 CXXConstructorDecl *Constructor,
485 AccessSpecifier Access) {
John McCall58e6f342010-03-16 05:22:47 +0000486 if (!getLangOptions().AccessControl ||
487 Access == AS_public)
John McCall6b2accb2010-02-10 09:31:12 +0000488 return AR_accessible;
John McCallb13b7372010-02-01 03:16:54 +0000489
John McCall6b2accb2010-02-10 09:31:12 +0000490 CXXRecordDecl *NamingClass = Constructor->getParent();
John McCall58e6f342010-03-16 05:22:47 +0000491 AccessedEntity Entity(AccessedEntity::Member,
492 NamingClass, Access, Constructor);
493 Entity.setDiag(diag::err_access_ctor);
494
495 return CheckAccess(*this, UseLoc, Entity);
John McCallb13b7372010-02-01 03:16:54 +0000496}
497
John McCallb0207482010-03-16 06:11:48 +0000498/// Checks direct (i.e. non-inherited) access to an arbitrary class
499/// member.
500Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
501 NamedDecl *Target,
502 const PartialDiagnostic &Diag) {
503 AccessSpecifier Access = Target->getAccess();
504 if (!getLangOptions().AccessControl ||
505 Access == AS_public)
506 return AR_accessible;
507
508 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext());
509 AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Target);
510 Entity.setDiag(Diag);
511 return CheckAccess(*this, UseLoc, Entity);
512}
513
514
John McCallb13b7372010-02-01 03:16:54 +0000515/// Checks access to an overloaded member operator, including
516/// conversion operators.
John McCall6b2accb2010-02-10 09:31:12 +0000517Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
518 Expr *ObjectExpr,
John McCall58e6f342010-03-16 05:22:47 +0000519 Expr *ArgExpr,
John McCall6b2accb2010-02-10 09:31:12 +0000520 NamedDecl *MemberOperator,
521 AccessSpecifier Access) {
John McCall58e6f342010-03-16 05:22:47 +0000522 if (!getLangOptions().AccessControl ||
523 Access == AS_public)
John McCall6b2accb2010-02-10 09:31:12 +0000524 return AR_accessible;
John McCall5357b612010-01-28 01:42:12 +0000525
526 const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
527 assert(RT && "found member operator but object expr not of record type");
528 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
529
John McCall58e6f342010-03-16 05:22:47 +0000530 AccessedEntity Entity(AccessedEntity::Member,
531 NamingClass, Access, MemberOperator);
532 Entity.setDiag(diag::err_access)
533 << ObjectExpr->getSourceRange()
534 << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
535
536 return CheckAccess(*this, OpLoc, Entity);
John McCall6b2accb2010-02-10 09:31:12 +0000537}
John McCall5357b612010-01-28 01:42:12 +0000538
John McCall6b2accb2010-02-10 09:31:12 +0000539/// Checks access for a hierarchy conversion.
540///
541/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
542/// or a derived-to-base conversion (false)
543/// \param ForceCheck true if this check should be performed even if access
544/// control is disabled; some things rely on this for semantics
545/// \param ForceUnprivileged true if this check should proceed as if the
546/// context had no special privileges
547/// \param ADK controls the kind of diagnostics that are used
548Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
John McCall6b2accb2010-02-10 09:31:12 +0000549 QualType Base,
550 QualType Derived,
551 const CXXBasePath &Path,
John McCall58e6f342010-03-16 05:22:47 +0000552 unsigned DiagID,
John McCall6b2accb2010-02-10 09:31:12 +0000553 bool ForceCheck,
John McCall58e6f342010-03-16 05:22:47 +0000554 bool ForceUnprivileged) {
John McCall6b2accb2010-02-10 09:31:12 +0000555 if (!ForceCheck && !getLangOptions().AccessControl)
556 return AR_accessible;
John McCall5357b612010-01-28 01:42:12 +0000557
John McCall6b2accb2010-02-10 09:31:12 +0000558 if (Path.Access == AS_public)
559 return AR_accessible;
John McCall5357b612010-01-28 01:42:12 +0000560
John McCall6b2accb2010-02-10 09:31:12 +0000561 CXXRecordDecl *BaseD, *DerivedD;
562 BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
563 DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
John McCall58e6f342010-03-16 05:22:47 +0000564
565 AccessedEntity Entity(AccessedEntity::Base, BaseD, DerivedD, Path.Access);
566 if (DiagID)
567 Entity.setDiag(DiagID) << Derived << Base;
John McCall6b2accb2010-02-10 09:31:12 +0000568
569 if (ForceUnprivileged)
John McCall58e6f342010-03-16 05:22:47 +0000570 return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity);
571 return CheckAccess(*this, AccessLoc, Entity);
John McCall5357b612010-01-28 01:42:12 +0000572}
573
John McCall92f88312010-01-23 00:46:32 +0000574/// Checks access to all the declarations in the given result set.
John McCall6b2accb2010-02-10 09:31:12 +0000575void Sema::CheckLookupAccess(const LookupResult &R) {
576 assert(getLangOptions().AccessControl
577 && "performing access check without access control");
578 assert(R.getNamingClass() && "performing access check without naming class");
579
John McCall58e6f342010-03-16 05:22:47 +0000580 for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
581 if (I.getAccess() != AS_public) {
582 AccessedEntity Entity(AccessedEntity::Member,
583 R.getNamingClass(), I.getAccess(), *I);
584 Entity.setDiag(diag::err_access);
585
586 CheckAccess(*this, R.getNameLoc(), Entity);
587 }
588 }
John McCall92f88312010-01-23 00:46:32 +0000589}