blob: 85c4662846b705ec7ebc22909f755343c0e6147f [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 {
55 EffectiveContext() : Record(0), 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;
63
64 if (isa<CXXRecordDecl>(DC))
65 Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
Anders Carlsson733d77f2009-03-27 06:03:27 +000066 else
John McCall5b0829a2010-02-10 09:31:12 +000067 Record = 0;
Anders Carlsson733d77f2009-03-27 06:03:27 +000068 }
Sebastian Redle644e192009-07-18 14:32:15 +000069
John McCall5b0829a2010-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 Carlsson4742a9c2009-03-27 05:05:05 +000077}
John McCall553c0792010-01-23 00:46:32 +000078
John McCall5b0829a2010-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 McCall16927f62010-03-12 01:19:31 +000089 // A class always has access to its own members.
John McCall5b0829a2010-02-10 09:31:12 +000090 if (EC.isClass(Class))
91 return Sema::AR_accessible;
92
John McCall16927f62010-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 McCall5b0829a2010-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 McCall553c0792010-01-23 00:46:32 +0000178 // Easy case: the decl's natural access determined its path access.
John McCall5b0829a2010-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
258 if (isa<CXXConstructorDecl>(D)) {
259 unsigned DiagID = (Access == AS_protected ? diag::err_access_ctor_protected
260 : diag::err_access_ctor_private);
261 S.Diag(Loc, DiagID)
262 << S.Context.getTypeDeclType(DeclaringClass);
263 } else {
264 unsigned DiagID = (Access == AS_protected ? diag::err_access_protected
265 : diag::err_access_private);
266 S.Diag(Loc, DiagID)
267 << D->getDeclName()
268 << S.Context.getTypeDeclType(DeclaringClass);
269 }
270 DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
271}
272
273/// Diagnose an inaccessible hierarchy conversion.
274static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc,
275 const EffectiveContext &EC,
276 AccessSpecifier Access,
277 const Sema::AccessedEntity &Entity,
278 Sema::AccessDiagnosticsKind ADK) {
279 if (ADK == Sema::ADK_covariance) {
280 S.Diag(Loc, diag::err_covariant_return_inaccessible_base)
281 << S.Context.getTypeDeclType(Entity.getDerivedClass())
282 << S.Context.getTypeDeclType(Entity.getBaseClass())
283 << (Access == AS_protected);
284 } else if (Entity.getKind() == Sema::AccessedEntity::BaseToDerivedConversion) {
285 S.Diag(Loc, diag::err_downcast_from_inaccessible_base)
286 << S.Context.getTypeDeclType(Entity.getDerivedClass())
287 << S.Context.getTypeDeclType(Entity.getBaseClass())
288 << (Access == AS_protected);
289 } else {
290 S.Diag(Loc, diag::err_upcast_to_inaccessible_base)
291 << S.Context.getTypeDeclType(Entity.getDerivedClass())
292 << S.Context.getTypeDeclType(Entity.getBaseClass())
293 << (Access == AS_protected);
294 }
295 DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
296 Entity.getBaseClass(), 0, Access);
297}
298
299static void DiagnoseBadAccess(Sema &S,
300 SourceLocation Loc,
301 const EffectiveContext &EC,
302 CXXRecordDecl *NamingClass,
303 AccessSpecifier Access,
304 const Sema::AccessedEntity &Entity,
305 Sema::AccessDiagnosticsKind ADK) {
306 if (Entity.isMemberAccess())
307 DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
308 else
309 DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity, ADK);
310}
311
312
313/// Try to elevate access using friend declarations. This is
314/// potentially quite expensive.
315static void TryElevateAccess(Sema &S,
316 const EffectiveContext &EC,
317 const Sema::AccessedEntity &Entity,
318 AccessSpecifier &Access) {
319 CXXRecordDecl *DeclaringClass;
320 if (Entity.isMemberAccess()) {
321 DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
322 } else {
323 DeclaringClass = Entity.getBaseClass();
324 }
325 CXXRecordDecl *NamingClass = Entity.getNamingClass();
326
327 // Adjust the declaration of the referred entity.
328 AccessSpecifier DeclAccess = AS_none;
329 if (Entity.isMemberAccess()) {
330 NamedDecl *Target = Entity.getTargetDecl();
331
332 DeclAccess = Target->getAccess();
333 if (DeclAccess != AS_public) {
334 switch (GetFriendKind(S, EC, DeclaringClass)) {
335 case Sema::AR_accessible: DeclAccess = AS_public; break;
336 case Sema::AR_inaccessible: break;
337 case Sema::AR_dependent: /* FIXME: delay dependent friendship */ return;
338 case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
339 }
340 }
341
342 if (DeclaringClass == NamingClass) {
343 Access = DeclAccess;
344 return;
345 }
346 }
347
348 assert(DeclaringClass != NamingClass);
349
350 // Append the declaration's access if applicable.
351 CXXBasePaths Paths;
352 CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(),
353 DeclaringClass, Paths);
354 if (!Path) {
355 // FIXME: delay dependent friendship
John McCall553c0792010-01-23 00:46:32 +0000356 return;
357 }
358
John McCall5b0829a2010-02-10 09:31:12 +0000359 // Grab the access along the best path.
360 AccessSpecifier NewAccess = Path->Access;
361 if (Entity.isMemberAccess())
362 NewAccess = CXXRecordDecl::MergeAccess(NewAccess, DeclAccess);
363
364 assert(NewAccess <= Access && "access along best path worse than direct?");
365 Access = NewAccess;
John McCall553c0792010-01-23 00:46:32 +0000366}
367
John McCall5b0829a2010-02-10 09:31:12 +0000368/// Checks access to an entity from the given effective context.
369static Sema::AccessResult CheckEffectiveAccess(Sema &S,
370 const EffectiveContext &EC,
371 SourceLocation Loc,
372 Sema::AccessedEntity const &Entity,
373 Sema::AccessDiagnosticsKind ADK) {
374 AccessSpecifier Access = Entity.getAccess();
375 assert(Access != AS_public);
John McCall553c0792010-01-23 00:46:32 +0000376
John McCall5b0829a2010-02-10 09:31:12 +0000377 CXXRecordDecl *NamingClass = Entity.getNamingClass();
John McCall553c0792010-01-23 00:46:32 +0000378 while (NamingClass->isAnonymousStructOrUnion())
379 // This should be guaranteed by the fact that the decl has
380 // non-public access. If not, we should make it guaranteed!
381 NamingClass = cast<CXXRecordDecl>(NamingClass);
382
John McCall5b0829a2010-02-10 09:31:12 +0000383 if (!EC.Record) {
384 TryElevateAccess(S, EC, Entity, Access);
385 if (Access == AS_public) return Sema::AR_accessible;
386
387 if (ADK != Sema::ADK_quiet)
388 DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
389 return Sema::AR_inaccessible;
390 }
391
John McCall553c0792010-01-23 00:46:32 +0000392 // White-list accesses from within the declaring class.
John McCall5b0829a2010-02-10 09:31:12 +0000393 if (Access != AS_none && EC.isClass(NamingClass))
394 return Sema::AR_accessible;
395
396 // If the access is worse than 'protected', try to promote to it using
397 // friend declarations.
398 bool TriedElevation = false;
399 if (Access != AS_protected) {
400 TryElevateAccess(S, EC, Entity, Access);
401 if (Access == AS_public) return Sema::AR_accessible;
402 TriedElevation = true;
403 }
John McCall553c0792010-01-23 00:46:32 +0000404
405 // Protected access.
406 if (Access == AS_protected) {
407 // FIXME: implement [class.protected]p1
John McCall5b0829a2010-02-10 09:31:12 +0000408 if (EC.Record->isDerivedFrom(NamingClass))
409 return Sema::AR_accessible;
John McCall553c0792010-01-23 00:46:32 +0000410
John McCall5b0829a2010-02-10 09:31:12 +0000411 // FIXME: delay dependent classes
John McCall553c0792010-01-23 00:46:32 +0000412 }
413
John McCall5b0829a2010-02-10 09:31:12 +0000414 // We're about to reject; one last chance to promote access.
415 if (!TriedElevation) {
416 TryElevateAccess(S, EC, Entity, Access);
417 if (Access == AS_public) return Sema::AR_accessible;
418 }
419
420 // Okay, that's it, reject it.
421 if (ADK != Sema::ADK_quiet)
422 DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
423 return Sema::AR_inaccessible;
424}
John McCall553c0792010-01-23 00:46:32 +0000425
John McCall5b0829a2010-02-10 09:31:12 +0000426static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
427 const Sema::AccessedEntity &Entity,
428 Sema::AccessDiagnosticsKind ADK
429 = Sema::ADK_normal) {
430 // If the access path is public, it's accessible everywhere.
431 if (Entity.getAccess() == AS_public)
432 return Sema::AR_accessible;
John McCall553c0792010-01-23 00:46:32 +0000433
John McCall5b0829a2010-02-10 09:31:12 +0000434 // If we're currently parsing a top-level declaration, delay
435 // diagnostics. This is the only case where parsing a declaration
436 // can actually change our effective context for the purposes of
437 // access control.
438 if (S.CurContext->isFileContext() && S.ParsingDeclDepth) {
439 assert(ADK == Sema::ADK_normal && "delaying abnormal access check");
440 S.DelayedDiagnostics.push_back(
441 Sema::DelayedDiagnostic::makeAccess(Loc, Entity));
442 return Sema::AR_delayed;
John McCall553c0792010-01-23 00:46:32 +0000443 }
444
John McCall5b0829a2010-02-10 09:31:12 +0000445 return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
446 Loc, Entity, ADK);
John McCall553c0792010-01-23 00:46:32 +0000447}
448
John McCall86121512010-01-27 03:50:35 +0000449void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
John McCall86121512010-01-27 03:50:35 +0000450 // Pretend we did this from the context of the newly-parsed
451 // declaration.
John McCall5b0829a2010-02-10 09:31:12 +0000452 EffectiveContext EC(Ctx->getDeclContext());
John McCall86121512010-01-27 03:50:35 +0000453
John McCall5b0829a2010-02-10 09:31:12 +0000454 if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.AccessData, ADK_normal))
John McCall86121512010-01-27 03:50:35 +0000455 DD.Triggered = true;
456}
457
John McCall5b0829a2010-02-10 09:31:12 +0000458Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
459 NamedDecl *D,
460 AccessSpecifier Access) {
John McCall58cc69d2010-01-27 01:50:18 +0000461 if (!getLangOptions().AccessControl || !E->getNamingClass())
John McCall5b0829a2010-02-10 09:31:12 +0000462 return AR_accessible;
John McCall58cc69d2010-01-27 01:50:18 +0000463
John McCall5b0829a2010-02-10 09:31:12 +0000464 return CheckAccess(*this, E->getNameLoc(),
465 AccessedEntity::makeMember(E->getNamingClass(), Access, D));
John McCall58cc69d2010-01-27 01:50:18 +0000466}
467
468/// Perform access-control checking on a previously-unresolved member
469/// access which has now been resolved to a member.
John McCall5b0829a2010-02-10 09:31:12 +0000470Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
471 NamedDecl *D,
472 AccessSpecifier Access) {
John McCall58cc69d2010-01-27 01:50:18 +0000473 if (!getLangOptions().AccessControl)
John McCall5b0829a2010-02-10 09:31:12 +0000474 return AR_accessible;
John McCall58cc69d2010-01-27 01:50:18 +0000475
John McCall5b0829a2010-02-10 09:31:12 +0000476 return CheckAccess(*this, E->getMemberLoc(),
477 AccessedEntity::makeMember(E->getNamingClass(), Access, D));
John McCall58cc69d2010-01-27 01:50:18 +0000478}
479
John McCall5b0829a2010-02-10 09:31:12 +0000480Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
481 const RecordType *RT) {
John McCall6781b052010-02-02 08:45:54 +0000482 if (!getLangOptions().AccessControl)
John McCall5b0829a2010-02-10 09:31:12 +0000483 return AR_accessible;
John McCall6781b052010-02-02 08:45:54 +0000484
John McCall03c48482010-02-02 09:10:11 +0000485 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
John McCall6781b052010-02-02 08:45:54 +0000486 CXXDestructorDecl *Dtor = NamingClass->getDestructor(Context);
487
488 AccessSpecifier Access = Dtor->getAccess();
489 if (Access == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000490 return AR_accessible;
John McCall6781b052010-02-02 08:45:54 +0000491
John McCall5b0829a2010-02-10 09:31:12 +0000492 return CheckAccess(*this, Loc,
493 AccessedEntity::makeMember(NamingClass, Access, Dtor));
John McCall6781b052010-02-02 08:45:54 +0000494}
495
John McCall760af172010-02-01 03:16:54 +0000496/// Checks access to a constructor.
John McCall5b0829a2010-02-10 09:31:12 +0000497Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
John McCall760af172010-02-01 03:16:54 +0000498 CXXConstructorDecl *Constructor,
499 AccessSpecifier Access) {
500 if (!getLangOptions().AccessControl)
John McCall5b0829a2010-02-10 09:31:12 +0000501 return AR_accessible;
John McCall760af172010-02-01 03:16:54 +0000502
John McCall5b0829a2010-02-10 09:31:12 +0000503 CXXRecordDecl *NamingClass = Constructor->getParent();
504 return CheckAccess(*this, UseLoc,
505 AccessedEntity::makeMember(NamingClass, Access, Constructor));
John McCall760af172010-02-01 03:16:54 +0000506}
507
508/// Checks access to an overloaded member operator, including
509/// conversion operators.
John McCall5b0829a2010-02-10 09:31:12 +0000510Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
511 Expr *ObjectExpr,
512 NamedDecl *MemberOperator,
513 AccessSpecifier Access) {
John McCallb3a44002010-01-28 01:42:12 +0000514 if (!getLangOptions().AccessControl)
John McCall5b0829a2010-02-10 09:31:12 +0000515 return AR_accessible;
John McCallb3a44002010-01-28 01:42:12 +0000516
517 const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
518 assert(RT && "found member operator but object expr not of record type");
519 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
520
John McCall5b0829a2010-02-10 09:31:12 +0000521 return CheckAccess(*this, OpLoc,
522 AccessedEntity::makeMember(NamingClass, Access, MemberOperator));
523}
John McCallb3a44002010-01-28 01:42:12 +0000524
John McCall5b0829a2010-02-10 09:31:12 +0000525/// Checks access for a hierarchy conversion.
526///
527/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
528/// or a derived-to-base conversion (false)
529/// \param ForceCheck true if this check should be performed even if access
530/// control is disabled; some things rely on this for semantics
531/// \param ForceUnprivileged true if this check should proceed as if the
532/// context had no special privileges
533/// \param ADK controls the kind of diagnostics that are used
534Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
535 bool IsBaseToDerived,
536 QualType Base,
537 QualType Derived,
538 const CXXBasePath &Path,
539 bool ForceCheck,
540 bool ForceUnprivileged,
541 AccessDiagnosticsKind ADK) {
542 if (!ForceCheck && !getLangOptions().AccessControl)
543 return AR_accessible;
John McCallb3a44002010-01-28 01:42:12 +0000544
John McCall5b0829a2010-02-10 09:31:12 +0000545 if (Path.Access == AS_public)
546 return AR_accessible;
John McCallb3a44002010-01-28 01:42:12 +0000547
John McCall5b0829a2010-02-10 09:31:12 +0000548 // TODO: preserve the information about which types exactly were used.
549 CXXRecordDecl *BaseD, *DerivedD;
550 BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
551 DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
552 AccessedEntity Entity = AccessedEntity::makeBaseClass(IsBaseToDerived,
553 BaseD, DerivedD,
554 Path.Access);
555
556 if (ForceUnprivileged)
557 return CheckEffectiveAccess(*this, EffectiveContext(),
558 AccessLoc, Entity, ADK);
559 return CheckAccess(*this, AccessLoc, Entity, ADK);
John McCallb3a44002010-01-28 01:42:12 +0000560}
561
John McCall553c0792010-01-23 00:46:32 +0000562/// Checks access to all the declarations in the given result set.
John McCall5b0829a2010-02-10 09:31:12 +0000563void Sema::CheckLookupAccess(const LookupResult &R) {
564 assert(getLangOptions().AccessControl
565 && "performing access check without access control");
566 assert(R.getNamingClass() && "performing access check without naming class");
567
John McCall553c0792010-01-23 00:46:32 +0000568 for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
John McCall5b0829a2010-02-10 09:31:12 +0000569 if (I.getAccess() != AS_public)
570 CheckAccess(*this, R.getNameLoc(),
571 AccessedEntity::makeMember(R.getNamingClass(),
572 I.getAccess(), *I));
John McCall553c0792010-01-23 00:46:32 +0000573}