blob: e7ec229d5271420744796090fea0ac7c64a113d5 [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
96static Sema::AccessResult GetFriendKind(Sema &S,
97 const EffectiveContext &EC,
98 const CXXRecordDecl *Class) {
John McCall16927f62010-03-12 01:19:31 +000099 // A class always has access to its own members.
John McCallfb803d72010-03-17 04:58:56 +0000100 if (EC.includesClass(Class))
John McCall5b0829a2010-02-10 09:31:12 +0000101 return Sema::AR_accessible;
102
John McCallfb803d72010-03-17 04:58:56 +0000103 Sema::AccessResult OnFailure = Sema::AR_inaccessible;
104
John McCall16927f62010-03-12 01:19:31 +0000105 // Okay, check friends.
106 for (CXXRecordDecl::friend_iterator I = Class->friend_begin(),
107 E = Class->friend_end(); I != E; ++I) {
108 FriendDecl *Friend = *I;
109
110 if (Type *T = Friend->getFriendType()) {
John McCallfb803d72010-03-17 04:58:56 +0000111 CanQualType CT = T->getCanonicalTypeUnqualified();
112 if (const RecordType *RT = CT->getAs<RecordType>())
113 if (EC.includesClass(cast<CXXRecordDecl>(RT->getDecl())))
114 return Sema::AR_accessible;
John McCall16927f62010-03-12 01:19:31 +0000115 } else {
116 NamedDecl *D
117 = cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl());
118
119 // The decl pointers in EC have been canonicalized, so pointer
120 // equality is sufficient.
John McCallfb803d72010-03-17 04:58:56 +0000121 if (D == EC.Function)
122 return Sema::AR_accessible;
123
124 if (isa<CXXRecordDecl>(D) &&
125 EC.includesClass(cast<CXXRecordDecl>(D)))
John McCall16927f62010-03-12 01:19:31 +0000126 return Sema::AR_accessible;
127 }
128
129 // FIXME: templates! templated contexts! dependent delay!
130 }
131
132 // That's it, give up.
John McCallfb803d72010-03-17 04:58:56 +0000133 return OnFailure;
John McCall5b0829a2010-02-10 09:31:12 +0000134}
135
136/// Finds the best path from the naming class to the declaring class,
137/// taking friend declarations into account.
138///
139/// \return null if friendship is dependent
140static CXXBasePath *FindBestPath(Sema &S,
141 const EffectiveContext &EC,
142 CXXRecordDecl *Derived,
143 CXXRecordDecl *Base,
144 CXXBasePaths &Paths) {
145 // Derive the paths to the desired base.
146 bool isDerived = Derived->isDerivedFrom(Base, Paths);
147 assert(isDerived && "derived class not actually derived from base");
148 (void) isDerived;
149
150 CXXBasePath *BestPath = 0;
151
152 // Derive the friend-modified access along each path.
153 for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
154 PI != PE; ++PI) {
155
156 // Walk through the path backwards.
157 AccessSpecifier PathAccess = AS_public;
158 CXXBasePath::iterator I = PI->end(), E = PI->begin();
159 while (I != E) {
160 --I;
161
162 AccessSpecifier BaseAccess = I->Base->getAccessSpecifier();
163 if (BaseAccess != AS_public) {
164 switch (GetFriendKind(S, EC, I->Class)) {
165 case Sema::AR_inaccessible: break;
166 case Sema::AR_accessible: BaseAccess = AS_public; break;
167 case Sema::AR_dependent: return 0;
168 case Sema::AR_delayed:
169 llvm_unreachable("friend resolution is never delayed"); break;
170 }
171 }
172
173 PathAccess = CXXRecordDecl::MergeAccess(BaseAccess, PathAccess);
174 }
175
176 // Note that we modify the path's Access field to the
177 // friend-modified access.
178 if (BestPath == 0 || PathAccess < BestPath->Access) {
179 BestPath = &*PI;
180 BestPath->Access = PathAccess;
181 }
182 }
183
184 return BestPath;
185}
186
187/// Diagnose the path which caused the given declaration or base class
188/// to become inaccessible.
189static void DiagnoseAccessPath(Sema &S,
190 const EffectiveContext &EC,
191 CXXRecordDecl *NamingClass,
192 CXXRecordDecl *DeclaringClass,
193 NamedDecl *D, AccessSpecifier Access) {
John McCall553c0792010-01-23 00:46:32 +0000194 // Easy case: the decl's natural access determined its path access.
John McCall5b0829a2010-02-10 09:31:12 +0000195 // We have to check against AS_private here in case Access is AS_none,
196 // indicating a non-public member of a private base class.
197 //
198 // DependentFriend should be impossible here.
199 if (D && (Access == D->getAccess() || D->getAccess() == AS_private)) {
200 switch (GetFriendKind(S, EC, DeclaringClass)) {
201 case Sema::AR_inaccessible: {
202 S.Diag(D->getLocation(), diag::note_access_natural)
203 << (unsigned) (Access == AS_protected)
204 << /*FIXME: not implicitly*/ 0;
205 return;
206 }
207
208 case Sema::AR_accessible: break;
209
210 case Sema::AR_dependent:
211 case Sema::AR_delayed:
212 llvm_unreachable("dependent/delayed not allowed");
213 return;
214 }
215 }
216
217 CXXBasePaths Paths;
218 CXXBasePath &Path = *FindBestPath(S, EC, NamingClass, DeclaringClass, Paths);
219
220 CXXBasePath::iterator I = Path.end(), E = Path.begin();
221 while (I != E) {
222 --I;
223
224 const CXXBaseSpecifier *BS = I->Base;
225 AccessSpecifier BaseAccess = BS->getAccessSpecifier();
226
227 // If this is public inheritance, or the derived class is a friend,
228 // skip this step.
229 if (BaseAccess == AS_public)
230 continue;
231
232 switch (GetFriendKind(S, EC, I->Class)) {
233 case Sema::AR_accessible: continue;
234 case Sema::AR_inaccessible: break;
235
236 case Sema::AR_dependent:
237 case Sema::AR_delayed:
238 llvm_unreachable("dependent friendship, should not be diagnosing");
239 }
240
241 // Check whether this base specifier is the tighest point
242 // constraining access. We have to check against AS_private for
243 // the same reasons as above.
244 if (BaseAccess == AS_private || BaseAccess >= Access) {
245
246 // We're constrained by inheritance, but we want to say
247 // "declared private here" if we're diagnosing a hierarchy
248 // conversion and this is the final step.
249 unsigned diagnostic;
250 if (D) diagnostic = diag::note_access_constrained_by_path;
251 else if (I + 1 == Path.end()) diagnostic = diag::note_access_natural;
252 else diagnostic = diag::note_access_constrained_by_path;
253
254 S.Diag(BS->getSourceRange().getBegin(), diagnostic)
255 << BS->getSourceRange()
256 << (BaseAccess == AS_protected)
257 << (BS->getAccessSpecifierAsWritten() == AS_none);
258 return;
259 }
260 }
261
262 llvm_unreachable("access not apparently constrained by path");
263}
264
265/// Diagnose an inaccessible class member.
266static void DiagnoseInaccessibleMember(Sema &S, SourceLocation Loc,
267 const EffectiveContext &EC,
268 CXXRecordDecl *NamingClass,
269 AccessSpecifier Access,
270 const Sema::AccessedEntity &Entity) {
271 NamedDecl *D = Entity.getTargetDecl();
272 CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
273
John McCall1064d7e2010-03-16 05:22:47 +0000274 S.Diag(Loc, Entity.getDiag())
275 << (Access == AS_protected)
276 << D->getDeclName()
277 << S.Context.getTypeDeclType(NamingClass)
278 << S.Context.getTypeDeclType(DeclaringClass);
John McCall5b0829a2010-02-10 09:31:12 +0000279 DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
280}
281
282/// Diagnose an inaccessible hierarchy conversion.
283static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc,
284 const EffectiveContext &EC,
285 AccessSpecifier Access,
John McCall1064d7e2010-03-16 05:22:47 +0000286 const Sema::AccessedEntity &Entity) {
287 S.Diag(Loc, Entity.getDiag())
288 << (Access == AS_protected)
289 << DeclarationName()
290 << S.Context.getTypeDeclType(Entity.getDerivedClass())
291 << S.Context.getTypeDeclType(Entity.getBaseClass());
John McCall5b0829a2010-02-10 09:31:12 +0000292 DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
293 Entity.getBaseClass(), 0, Access);
294}
295
John McCall1064d7e2010-03-16 05:22:47 +0000296static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
John McCall5b0829a2010-02-10 09:31:12 +0000297 const EffectiveContext &EC,
298 CXXRecordDecl *NamingClass,
299 AccessSpecifier Access,
John McCall1064d7e2010-03-16 05:22:47 +0000300 const Sema::AccessedEntity &Entity) {
John McCall5b0829a2010-02-10 09:31:12 +0000301 if (Entity.isMemberAccess())
302 DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
303 else
John McCall1064d7e2010-03-16 05:22:47 +0000304 DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity);
John McCall5b0829a2010-02-10 09:31:12 +0000305}
306
307
308/// Try to elevate access using friend declarations. This is
309/// potentially quite expensive.
310static void TryElevateAccess(Sema &S,
311 const EffectiveContext &EC,
312 const Sema::AccessedEntity &Entity,
313 AccessSpecifier &Access) {
314 CXXRecordDecl *DeclaringClass;
315 if (Entity.isMemberAccess()) {
316 DeclaringClass = FindDeclaringClass(Entity.getTargetDecl());
317 } else {
318 DeclaringClass = Entity.getBaseClass();
319 }
320 CXXRecordDecl *NamingClass = Entity.getNamingClass();
321
322 // Adjust the declaration of the referred entity.
323 AccessSpecifier DeclAccess = AS_none;
324 if (Entity.isMemberAccess()) {
325 NamedDecl *Target = Entity.getTargetDecl();
326
327 DeclAccess = Target->getAccess();
328 if (DeclAccess != AS_public) {
329 switch (GetFriendKind(S, EC, DeclaringClass)) {
330 case Sema::AR_accessible: DeclAccess = AS_public; break;
331 case Sema::AR_inaccessible: break;
332 case Sema::AR_dependent: /* FIXME: delay dependent friendship */ return;
333 case Sema::AR_delayed: llvm_unreachable("friend status is never delayed");
334 }
335 }
336
337 if (DeclaringClass == NamingClass) {
338 Access = DeclAccess;
339 return;
340 }
341 }
342
343 assert(DeclaringClass != NamingClass);
344
345 // Append the declaration's access if applicable.
346 CXXBasePaths Paths;
347 CXXBasePath *Path = FindBestPath(S, EC, Entity.getNamingClass(),
348 DeclaringClass, Paths);
349 if (!Path) {
350 // FIXME: delay dependent friendship
John McCall553c0792010-01-23 00:46:32 +0000351 return;
352 }
353
John McCall5b0829a2010-02-10 09:31:12 +0000354 // Grab the access along the best path.
355 AccessSpecifier NewAccess = Path->Access;
356 if (Entity.isMemberAccess())
357 NewAccess = CXXRecordDecl::MergeAccess(NewAccess, DeclAccess);
358
359 assert(NewAccess <= Access && "access along best path worse than direct?");
360 Access = NewAccess;
John McCall553c0792010-01-23 00:46:32 +0000361}
362
John McCall5b0829a2010-02-10 09:31:12 +0000363/// Checks access to an entity from the given effective context.
364static Sema::AccessResult CheckEffectiveAccess(Sema &S,
365 const EffectiveContext &EC,
366 SourceLocation Loc,
John McCall1064d7e2010-03-16 05:22:47 +0000367 Sema::AccessedEntity const &Entity) {
John McCall5b0829a2010-02-10 09:31:12 +0000368 AccessSpecifier Access = Entity.getAccess();
John McCallfb803d72010-03-17 04:58:56 +0000369 assert(Access != AS_public && "called for public access!");
John McCall553c0792010-01-23 00:46:32 +0000370
John McCallfb803d72010-03-17 04:58:56 +0000371 // Find a non-anonymous naming class. For records with access,
372 // there should always be one of these.
John McCall5b0829a2010-02-10 09:31:12 +0000373 CXXRecordDecl *NamingClass = Entity.getNamingClass();
John McCall553c0792010-01-23 00:46:32 +0000374 while (NamingClass->isAnonymousStructOrUnion())
John McCall1064d7e2010-03-16 05:22:47 +0000375 NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
John McCall553c0792010-01-23 00:46:32 +0000376
John McCallfb803d72010-03-17 04:58:56 +0000377 // White-list accesses from classes with privileges equivalent to the
378 // naming class --- but only if the access path isn't forbidden
379 // (i.e. an access of a private member from a subclass).
380 if (Access != AS_none && EC.includesClass(NamingClass))
John McCall5b0829a2010-02-10 09:31:12 +0000381 return Sema::AR_accessible;
John McCallfb803d72010-03-17 04:58:56 +0000382
383 // Try to elevate access.
384 // FIXME: delay if elevation was dependent?
385 // TODO: on some code, it might be better to do the protected check
386 // without trying to elevate first.
387 TryElevateAccess(S, EC, Entity, Access);
388 if (Access == AS_public) return Sema::AR_accessible;
John McCall553c0792010-01-23 00:46:32 +0000389
390 // Protected access.
391 if (Access == AS_protected) {
392 // FIXME: implement [class.protected]p1
John McCallfb803d72010-03-17 04:58:56 +0000393 for (llvm::SmallVectorImpl<CXXRecordDecl*>::const_iterator
394 I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I)
395 if ((*I)->isDerivedFrom(NamingClass))
396 return Sema::AR_accessible;
John McCall553c0792010-01-23 00:46:32 +0000397
John McCallfb803d72010-03-17 04:58:56 +0000398 // FIXME: delay if we can't decide class derivation yet.
John McCall553c0792010-01-23 00:46:32 +0000399 }
400
John McCall5b0829a2010-02-10 09:31:12 +0000401 // Okay, that's it, reject it.
John McCall1064d7e2010-03-16 05:22:47 +0000402 if (!Entity.isQuiet())
403 DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
John McCall5b0829a2010-02-10 09:31:12 +0000404 return Sema::AR_inaccessible;
405}
John McCall553c0792010-01-23 00:46:32 +0000406
John McCall5b0829a2010-02-10 09:31:12 +0000407static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
John McCall1064d7e2010-03-16 05:22:47 +0000408 const Sema::AccessedEntity &Entity) {
John McCall5b0829a2010-02-10 09:31:12 +0000409 // If the access path is public, it's accessible everywhere.
410 if (Entity.getAccess() == AS_public)
411 return Sema::AR_accessible;
John McCall553c0792010-01-23 00:46:32 +0000412
John McCall5b0829a2010-02-10 09:31:12 +0000413 // If we're currently parsing a top-level declaration, delay
414 // diagnostics. This is the only case where parsing a declaration
415 // can actually change our effective context for the purposes of
416 // access control.
417 if (S.CurContext->isFileContext() && S.ParsingDeclDepth) {
John McCall5b0829a2010-02-10 09:31:12 +0000418 S.DelayedDiagnostics.push_back(
419 Sema::DelayedDiagnostic::makeAccess(Loc, Entity));
420 return Sema::AR_delayed;
John McCall553c0792010-01-23 00:46:32 +0000421 }
422
John McCall5b0829a2010-02-10 09:31:12 +0000423 return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
John McCall1064d7e2010-03-16 05:22:47 +0000424 Loc, Entity);
John McCall553c0792010-01-23 00:46:32 +0000425}
426
John McCall86121512010-01-27 03:50:35 +0000427void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
John McCall86121512010-01-27 03:50:35 +0000428 // Pretend we did this from the context of the newly-parsed
429 // declaration.
John McCall5b0829a2010-02-10 09:31:12 +0000430 EffectiveContext EC(Ctx->getDeclContext());
John McCall86121512010-01-27 03:50:35 +0000431
John McCall1064d7e2010-03-16 05:22:47 +0000432 if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData()))
John McCall86121512010-01-27 03:50:35 +0000433 DD.Triggered = true;
434}
435
John McCall5b0829a2010-02-10 09:31:12 +0000436Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
437 NamedDecl *D,
438 AccessSpecifier Access) {
John McCall1064d7e2010-03-16 05:22:47 +0000439 if (!getLangOptions().AccessControl ||
440 !E->getNamingClass() ||
441 Access == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000442 return AR_accessible;
John McCall58cc69d2010-01-27 01:50:18 +0000443
John McCall1064d7e2010-03-16 05:22:47 +0000444 AccessedEntity Entity(AccessedEntity::Member,
445 E->getNamingClass(), Access, D);
446 Entity.setDiag(diag::err_access) << E->getSourceRange();
447
448 return CheckAccess(*this, E->getNameLoc(), Entity);
John McCall58cc69d2010-01-27 01:50:18 +0000449}
450
451/// Perform access-control checking on a previously-unresolved member
452/// access which has now been resolved to a member.
John McCall5b0829a2010-02-10 09:31:12 +0000453Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
454 NamedDecl *D,
455 AccessSpecifier Access) {
John McCall1064d7e2010-03-16 05:22:47 +0000456 if (!getLangOptions().AccessControl ||
457 Access == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000458 return AR_accessible;
John McCall58cc69d2010-01-27 01:50:18 +0000459
John McCall1064d7e2010-03-16 05:22:47 +0000460 AccessedEntity Entity(AccessedEntity::Member,
461 E->getNamingClass(), Access, D);
462 Entity.setDiag(diag::err_access) << E->getSourceRange();
463
464 return CheckAccess(*this, E->getMemberLoc(), Entity);
John McCall58cc69d2010-01-27 01:50:18 +0000465}
466
John McCall5b0829a2010-02-10 09:31:12 +0000467Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
John McCall1064d7e2010-03-16 05:22:47 +0000468 CXXDestructorDecl *Dtor,
469 const PartialDiagnostic &PDiag) {
John McCall6781b052010-02-02 08:45:54 +0000470 if (!getLangOptions().AccessControl)
John McCall5b0829a2010-02-10 09:31:12 +0000471 return AR_accessible;
John McCall6781b052010-02-02 08:45:54 +0000472
John McCall1064d7e2010-03-16 05:22:47 +0000473 // There's never a path involved when checking implicit destructor access.
John McCall6781b052010-02-02 08:45:54 +0000474 AccessSpecifier Access = Dtor->getAccess();
475 if (Access == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000476 return AR_accessible;
John McCall6781b052010-02-02 08:45:54 +0000477
John McCall1064d7e2010-03-16 05:22:47 +0000478 CXXRecordDecl *NamingClass = Dtor->getParent();
479 AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Dtor);
480 Entity.setDiag(PDiag); // TODO: avoid copy
481
482 return CheckAccess(*this, Loc, Entity);
John McCall6781b052010-02-02 08:45:54 +0000483}
484
John McCall760af172010-02-01 03:16:54 +0000485/// Checks access to a constructor.
John McCall5b0829a2010-02-10 09:31:12 +0000486Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
John McCall760af172010-02-01 03:16:54 +0000487 CXXConstructorDecl *Constructor,
488 AccessSpecifier Access) {
John McCall1064d7e2010-03-16 05:22:47 +0000489 if (!getLangOptions().AccessControl ||
490 Access == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000491 return AR_accessible;
John McCall760af172010-02-01 03:16:54 +0000492
John McCall5b0829a2010-02-10 09:31:12 +0000493 CXXRecordDecl *NamingClass = Constructor->getParent();
John McCall1064d7e2010-03-16 05:22:47 +0000494 AccessedEntity Entity(AccessedEntity::Member,
495 NamingClass, Access, Constructor);
496 Entity.setDiag(diag::err_access_ctor);
497
498 return CheckAccess(*this, UseLoc, Entity);
John McCall760af172010-02-01 03:16:54 +0000499}
500
John McCallab8c2732010-03-16 06:11:48 +0000501/// Checks direct (i.e. non-inherited) access to an arbitrary class
502/// member.
503Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
504 NamedDecl *Target,
505 const PartialDiagnostic &Diag) {
506 AccessSpecifier Access = Target->getAccess();
507 if (!getLangOptions().AccessControl ||
508 Access == AS_public)
509 return AR_accessible;
510
511 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext());
512 AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Target);
513 Entity.setDiag(Diag);
514 return CheckAccess(*this, UseLoc, Entity);
515}
516
517
John McCall760af172010-02-01 03:16:54 +0000518/// Checks access to an overloaded member operator, including
519/// conversion operators.
John McCall5b0829a2010-02-10 09:31:12 +0000520Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
521 Expr *ObjectExpr,
John McCall1064d7e2010-03-16 05:22:47 +0000522 Expr *ArgExpr,
John McCall5b0829a2010-02-10 09:31:12 +0000523 NamedDecl *MemberOperator,
524 AccessSpecifier Access) {
John McCall1064d7e2010-03-16 05:22:47 +0000525 if (!getLangOptions().AccessControl ||
526 Access == AS_public)
John McCall5b0829a2010-02-10 09:31:12 +0000527 return AR_accessible;
John McCallb3a44002010-01-28 01:42:12 +0000528
529 const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
530 assert(RT && "found member operator but object expr not of record type");
531 CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
532
John McCall1064d7e2010-03-16 05:22:47 +0000533 AccessedEntity Entity(AccessedEntity::Member,
534 NamingClass, Access, MemberOperator);
535 Entity.setDiag(diag::err_access)
536 << ObjectExpr->getSourceRange()
537 << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
538
539 return CheckAccess(*this, OpLoc, Entity);
John McCall5b0829a2010-02-10 09:31:12 +0000540}
John McCallb3a44002010-01-28 01:42:12 +0000541
John McCall5b0829a2010-02-10 09:31:12 +0000542/// Checks access for a hierarchy conversion.
543///
544/// \param IsBaseToDerived whether this is a base-to-derived conversion (true)
545/// or a derived-to-base conversion (false)
546/// \param ForceCheck true if this check should be performed even if access
547/// control is disabled; some things rely on this for semantics
548/// \param ForceUnprivileged true if this check should proceed as if the
549/// context had no special privileges
550/// \param ADK controls the kind of diagnostics that are used
551Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
John McCall5b0829a2010-02-10 09:31:12 +0000552 QualType Base,
553 QualType Derived,
554 const CXXBasePath &Path,
John McCall1064d7e2010-03-16 05:22:47 +0000555 unsigned DiagID,
John McCall5b0829a2010-02-10 09:31:12 +0000556 bool ForceCheck,
John McCall1064d7e2010-03-16 05:22:47 +0000557 bool ForceUnprivileged) {
John McCall5b0829a2010-02-10 09:31:12 +0000558 if (!ForceCheck && !getLangOptions().AccessControl)
559 return AR_accessible;
John McCallb3a44002010-01-28 01:42:12 +0000560
John McCall5b0829a2010-02-10 09:31:12 +0000561 if (Path.Access == AS_public)
562 return AR_accessible;
John McCallb3a44002010-01-28 01:42:12 +0000563
John McCall5b0829a2010-02-10 09:31:12 +0000564 CXXRecordDecl *BaseD, *DerivedD;
565 BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
566 DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
John McCall1064d7e2010-03-16 05:22:47 +0000567
568 AccessedEntity Entity(AccessedEntity::Base, BaseD, DerivedD, Path.Access);
569 if (DiagID)
570 Entity.setDiag(DiagID) << Derived << Base;
John McCall5b0829a2010-02-10 09:31:12 +0000571
572 if (ForceUnprivileged)
John McCall1064d7e2010-03-16 05:22:47 +0000573 return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity);
574 return CheckAccess(*this, AccessLoc, Entity);
John McCallb3a44002010-01-28 01:42:12 +0000575}
576
John McCall553c0792010-01-23 00:46:32 +0000577/// Checks access to all the declarations in the given result set.
John McCall5b0829a2010-02-10 09:31:12 +0000578void Sema::CheckLookupAccess(const LookupResult &R) {
579 assert(getLangOptions().AccessControl
580 && "performing access check without access control");
581 assert(R.getNamingClass() && "performing access check without naming class");
582
John McCall1064d7e2010-03-16 05:22:47 +0000583 for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
584 if (I.getAccess() != AS_public) {
585 AccessedEntity Entity(AccessedEntity::Member,
586 R.getNamingClass(), I.getAccess(), *I);
587 Entity.setDiag(diag::err_access);
588
589 CheckAccess(*this, R.getNameLoc(), Entity);
590 }
591 }
John McCall553c0792010-01-23 00:46:32 +0000592}