| Anders Carlsson | 4742a9c | 2009-03-27 05:05:05 +0000 | [diff] [blame] | 1 | //===---- SemaAccess.cpp - C++ Access Control -------------------*- C++ -*-===// | 
| Anders Carlsson | 8ed6f36 | 2009-03-27 04:43:36 +0000 | [diff] [blame] | 2 | // | 
| Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame] | 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | 4 | // See https://llvm.org/LICENSE.txt for license information. | 
|  | 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
| Anders Carlsson | 8ed6f36 | 2009-03-27 04:43:36 +0000 | [diff] [blame] | 6 | // | 
|  | 7 | //===----------------------------------------------------------------------===// | 
|  | 8 | // | 
|  | 9 | // This file provides Sema routines for C++ access control semantics. | 
|  | 10 | // | 
|  | 11 | //===----------------------------------------------------------------------===// | 
| Anders Carlsson | 1794112 | 2009-03-27 04:54:36 +0000 | [diff] [blame] | 12 |  | 
| Eric Liu | 18b404a | 2018-07-19 13:32:00 +0000 | [diff] [blame] | 13 | #include "clang/Basic/Specifiers.h" | 
| John McCall | 8302463 | 2010-08-25 22:03:47 +0000 | [diff] [blame] | 14 | #include "clang/Sema/SemaInternal.h" | 
| Anders Carlsson | 733d77f | 2009-03-27 06:03:27 +0000 | [diff] [blame] | 15 | #include "clang/AST/ASTContext.h" | 
| Douglas Gregor | 36d1b14 | 2009-10-06 17:59:45 +0000 | [diff] [blame] | 16 | #include "clang/AST/CXXInheritance.h" | 
|  | 17 | #include "clang/AST/DeclCXX.h" | 
| John McCall | 16927f6 | 2010-03-12 01:19:31 +0000 | [diff] [blame] | 18 | #include "clang/AST/DeclFriend.h" | 
| Douglas Gregor | 21ceb18 | 2011-11-03 19:00:24 +0000 | [diff] [blame] | 19 | #include "clang/AST/DeclObjC.h" | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 20 | #include "clang/AST/DependentDiagnostic.h" | 
| John McCall | 58cc69d | 2010-01-27 01:50:18 +0000 | [diff] [blame] | 21 | #include "clang/AST/ExprCXX.h" | 
| Chandler Carruth | 3a02247 | 2012-12-04 09:13:33 +0000 | [diff] [blame] | 22 | #include "clang/Sema/DelayedDiagnostic.h" | 
|  | 23 | #include "clang/Sema/Initialization.h" | 
|  | 24 | #include "clang/Sema/Lookup.h" | 
| John McCall | 58cc69d | 2010-01-27 01:50:18 +0000 | [diff] [blame] | 25 |  | 
| Anders Carlsson | 1794112 | 2009-03-27 04:54:36 +0000 | [diff] [blame] | 26 | using namespace clang; | 
| John McCall | b45a1e7 | 2010-08-26 02:13:20 +0000 | [diff] [blame] | 27 | using namespace sema; | 
| Anders Carlsson | 1794112 | 2009-03-27 04:54:36 +0000 | [diff] [blame] | 28 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 29 | /// A copy of Sema's enum without AR_delayed. | 
|  | 30 | enum AccessResult { | 
|  | 31 | AR_accessible, | 
|  | 32 | AR_inaccessible, | 
|  | 33 | AR_dependent | 
|  | 34 | }; | 
|  | 35 |  | 
| Anders Carlsson | 4742a9c | 2009-03-27 05:05:05 +0000 | [diff] [blame] | 36 | /// SetMemberAccessSpecifier - Set the access specifier of a member. | 
|  | 37 | /// Returns true on error (when the previous member decl access specifier | 
|  | 38 | /// is different from the new member decl access specifier). | 
| Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 39 | bool Sema::SetMemberAccessSpecifier(NamedDecl *MemberDecl, | 
| Anders Carlsson | 1794112 | 2009-03-27 04:54:36 +0000 | [diff] [blame] | 40 | NamedDecl *PrevMemberDecl, | 
|  | 41 | AccessSpecifier LexicalAS) { | 
|  | 42 | if (!PrevMemberDecl) { | 
|  | 43 | // Use the lexical access specifier. | 
|  | 44 | MemberDecl->setAccess(LexicalAS); | 
|  | 45 | return false; | 
|  | 46 | } | 
| Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 47 |  | 
| Anders Carlsson | 1794112 | 2009-03-27 04:54:36 +0000 | [diff] [blame] | 48 | // C++ [class.access.spec]p3: When a member is redeclared its access | 
|  | 49 | // specifier must be same as its initial declaration. | 
|  | 50 | if (LexicalAS != AS_none && LexicalAS != PrevMemberDecl->getAccess()) { | 
| Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 51 | Diag(MemberDecl->getLocation(), | 
|  | 52 | diag::err_class_redeclared_with_different_access) | 
| Anders Carlsson | 1794112 | 2009-03-27 04:54:36 +0000 | [diff] [blame] | 53 | << MemberDecl << LexicalAS; | 
|  | 54 | Diag(PrevMemberDecl->getLocation(), diag::note_previous_access_declaration) | 
|  | 55 | << PrevMemberDecl << PrevMemberDecl->getAccess(); | 
| John McCall | 0a4bb26 | 2009-12-23 00:37:40 +0000 | [diff] [blame] | 56 |  | 
|  | 57 | MemberDecl->setAccess(LexicalAS); | 
| Anders Carlsson | 1794112 | 2009-03-27 04:54:36 +0000 | [diff] [blame] | 58 | return true; | 
|  | 59 | } | 
| Mike Stump | 11289f4 | 2009-09-09 15:08:12 +0000 | [diff] [blame] | 60 |  | 
| Anders Carlsson | 1794112 | 2009-03-27 04:54:36 +0000 | [diff] [blame] | 61 | MemberDecl->setAccess(PrevMemberDecl->getAccess()); | 
|  | 62 | return false; | 
|  | 63 | } | 
| Anders Carlsson | 4742a9c | 2009-03-27 05:05:05 +0000 | [diff] [blame] | 64 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 65 | static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { | 
|  | 66 | DeclContext *DC = D->getDeclContext(); | 
|  | 67 |  | 
|  | 68 | // This can only happen at top: enum decls only "publish" their | 
|  | 69 | // immediate members. | 
|  | 70 | if (isa<EnumDecl>(DC)) | 
|  | 71 | DC = cast<EnumDecl>(DC)->getDeclContext(); | 
|  | 72 |  | 
|  | 73 | CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(DC); | 
|  | 74 | while (DeclaringClass->isAnonymousStructOrUnion()) | 
|  | 75 | DeclaringClass = cast<CXXRecordDecl>(DeclaringClass->getDeclContext()); | 
|  | 76 | return DeclaringClass; | 
|  | 77 | } | 
|  | 78 |  | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 79 | namespace { | 
|  | 80 | struct EffectiveContext { | 
| Craig Topper | c3ec149 | 2014-05-26 06:22:03 +0000 | [diff] [blame] | 81 | EffectiveContext() : Inner(nullptr), Dependent(false) {} | 
| Anders Carlsson | 733d77f | 2009-03-27 06:03:27 +0000 | [diff] [blame] | 82 |  | 
| John McCall | 816d75b | 2010-03-24 07:46:06 +0000 | [diff] [blame] | 83 | explicit EffectiveContext(DeclContext *DC) | 
|  | 84 | : Inner(DC), | 
|  | 85 | Dependent(DC->isDependentContext()) { | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 86 |  | 
| Richard Smith | ad5c1ca | 2013-04-29 10:13:55 +0000 | [diff] [blame] | 87 | // C++11 [class.access.nest]p1: | 
| John McCall | fb803d7 | 2010-03-17 04:58:56 +0000 | [diff] [blame] | 88 | //   A nested class is a member and as such has the same access | 
|  | 89 | //   rights as any other member. | 
| Richard Smith | ad5c1ca | 2013-04-29 10:13:55 +0000 | [diff] [blame] | 90 | // C++11 [class.access]p2: | 
| John McCall | fb803d7 | 2010-03-17 04:58:56 +0000 | [diff] [blame] | 91 | //   A member of a class can also access all the names to which | 
| John McCall | 3dc81f7 | 2010-03-27 06:55:49 +0000 | [diff] [blame] | 92 | //   the class has access.  A local class of a member function | 
|  | 93 | //   may access the same names that the member function itself | 
|  | 94 | //   may access. | 
|  | 95 | // This almost implies that the privileges of nesting are transitive. | 
|  | 96 | // Technically it says nothing about the local classes of non-member | 
|  | 97 | // functions (which can gain privileges through friendship), but we | 
|  | 98 | // take that as an oversight. | 
|  | 99 | while (true) { | 
| John McCall | e91aec7 | 2012-08-24 22:54:02 +0000 | [diff] [blame] | 100 | // We want to add canonical declarations to the EC lists for | 
|  | 101 | // simplicity of checking, but we need to walk up through the | 
|  | 102 | // actual current DC chain.  Otherwise, something like a local | 
|  | 103 | // extern or friend which happens to be the canonical | 
|  | 104 | // declaration will really mess us up. | 
|  | 105 |  | 
| John McCall | 3dc81f7 | 2010-03-27 06:55:49 +0000 | [diff] [blame] | 106 | if (isa<CXXRecordDecl>(DC)) { | 
| John McCall | e91aec7 | 2012-08-24 22:54:02 +0000 | [diff] [blame] | 107 | CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); | 
|  | 108 | Records.push_back(Record->getCanonicalDecl()); | 
| John McCall | 3dc81f7 | 2010-03-27 06:55:49 +0000 | [diff] [blame] | 109 | DC = Record->getDeclContext(); | 
|  | 110 | } else if (isa<FunctionDecl>(DC)) { | 
| John McCall | e91aec7 | 2012-08-24 22:54:02 +0000 | [diff] [blame] | 111 | FunctionDecl *Function = cast<FunctionDecl>(DC); | 
|  | 112 | Functions.push_back(Function->getCanonicalDecl()); | 
| Douglas Gregor | 5663658 | 2011-10-09 22:38:36 +0000 | [diff] [blame] | 113 | if (Function->getFriendObjectKind()) | 
|  | 114 | DC = Function->getLexicalDeclContext(); | 
|  | 115 | else | 
|  | 116 | DC = Function->getDeclContext(); | 
| John McCall | 3dc81f7 | 2010-03-27 06:55:49 +0000 | [diff] [blame] | 117 | } else if (DC->isFileContext()) { | 
|  | 118 | break; | 
|  | 119 | } else { | 
|  | 120 | DC = DC->getParent(); | 
|  | 121 | } | 
| John McCall | fb803d7 | 2010-03-17 04:58:56 +0000 | [diff] [blame] | 122 | } | 
| Anders Carlsson | 733d77f | 2009-03-27 06:03:27 +0000 | [diff] [blame] | 123 | } | 
| Sebastian Redl | e644e19 | 2009-07-18 14:32:15 +0000 | [diff] [blame] | 124 |  | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 125 | bool isDependent() const { return Dependent; } | 
|  | 126 |  | 
| John McCall | fb803d7 | 2010-03-17 04:58:56 +0000 | [diff] [blame] | 127 | bool includesClass(const CXXRecordDecl *R) const { | 
|  | 128 | R = R->getCanonicalDecl(); | 
| Fangrui Song | 75e74e0 | 2019-03-31 08:48:19 +0000 | [diff] [blame] | 129 | return llvm::find(Records, R) != Records.end(); | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 130 | } | 
|  | 131 |  | 
| John McCall | 816d75b | 2010-03-24 07:46:06 +0000 | [diff] [blame] | 132 | /// Retrieves the innermost "useful" context.  Can be null if we're | 
|  | 133 | /// doing access-control without privileges. | 
|  | 134 | DeclContext *getInnerContext() const { | 
|  | 135 | return Inner; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 136 | } | 
|  | 137 |  | 
| Chris Lattner | 0e62c1c | 2011-07-23 10:55:15 +0000 | [diff] [blame] | 138 | typedef SmallVectorImpl<CXXRecordDecl*>::const_iterator record_iterator; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 139 |  | 
| John McCall | 816d75b | 2010-03-24 07:46:06 +0000 | [diff] [blame] | 140 | DeclContext *Inner; | 
| Chris Lattner | 0e62c1c | 2011-07-23 10:55:15 +0000 | [diff] [blame] | 141 | SmallVector<FunctionDecl*, 4> Functions; | 
|  | 142 | SmallVector<CXXRecordDecl*, 4> Records; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 143 | bool Dependent; | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 144 | }; | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 145 |  | 
| Nico Weber | 20c9f1d | 2010-11-28 22:53:37 +0000 | [diff] [blame] | 146 | /// Like sema::AccessedEntity, but kindly lets us scribble all over | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 147 | /// it. | 
| John McCall | b45a1e7 | 2010-08-26 02:13:20 +0000 | [diff] [blame] | 148 | struct AccessTarget : public AccessedEntity { | 
|  | 149 | AccessTarget(const AccessedEntity &Entity) | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 150 | : AccessedEntity(Entity) { | 
|  | 151 | initialize(); | 
|  | 152 | } | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 153 |  | 
|  | 154 | AccessTarget(ASTContext &Context, | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 155 | MemberNonce _, | 
|  | 156 | CXXRecordDecl *NamingClass, | 
|  | 157 | DeclAccessPair FoundDecl, | 
| Erik Verbruggen | 631dfc6 | 2011-09-19 15:10:40 +0000 | [diff] [blame] | 158 | QualType BaseObjectType) | 
| Benjamin Kramer | 1ea8e09 | 2012-07-04 17:04:04 +0000 | [diff] [blame] | 159 | : AccessedEntity(Context.getDiagAllocator(), Member, NamingClass, | 
|  | 160 | FoundDecl, BaseObjectType) { | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 161 | initialize(); | 
|  | 162 | } | 
|  | 163 |  | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 164 | AccessTarget(ASTContext &Context, | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 165 | BaseNonce _, | 
|  | 166 | CXXRecordDecl *BaseClass, | 
|  | 167 | CXXRecordDecl *DerivedClass, | 
|  | 168 | AccessSpecifier Access) | 
| Benjamin Kramer | 1ea8e09 | 2012-07-04 17:04:04 +0000 | [diff] [blame] | 169 | : AccessedEntity(Context.getDiagAllocator(), Base, BaseClass, DerivedClass, | 
|  | 170 | Access) { | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 171 | initialize(); | 
|  | 172 | } | 
|  | 173 |  | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 174 | bool isInstanceMember() const { | 
|  | 175 | return (isMemberAccess() && getTargetDecl()->isCXXInstanceMember()); | 
|  | 176 | } | 
|  | 177 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 178 | bool hasInstanceContext() const { | 
|  | 179 | return HasInstanceContext; | 
|  | 180 | } | 
|  | 181 |  | 
|  | 182 | class SavedInstanceContext { | 
|  | 183 | public: | 
| David Blaikie | 8533e96 | 2015-08-12 22:58:10 +0000 | [diff] [blame] | 184 | SavedInstanceContext(SavedInstanceContext &&S) | 
|  | 185 | : Target(S.Target), Has(S.Has) { | 
|  | 186 | S.Target = nullptr; | 
|  | 187 | } | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 188 | ~SavedInstanceContext() { | 
| David Blaikie | 8533e96 | 2015-08-12 22:58:10 +0000 | [diff] [blame] | 189 | if (Target) | 
|  | 190 | Target->HasInstanceContext = Has; | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 191 | } | 
|  | 192 |  | 
|  | 193 | private: | 
| John McCall | 8e36d53 | 2010-04-07 00:41:46 +0000 | [diff] [blame] | 194 | friend struct AccessTarget; | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 195 | explicit SavedInstanceContext(AccessTarget &Target) | 
| David Blaikie | 8533e96 | 2015-08-12 22:58:10 +0000 | [diff] [blame] | 196 | : Target(&Target), Has(Target.HasInstanceContext) {} | 
|  | 197 | AccessTarget *Target; | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 198 | bool Has; | 
|  | 199 | }; | 
|  | 200 |  | 
|  | 201 | SavedInstanceContext saveInstanceContext() { | 
|  | 202 | return SavedInstanceContext(*this); | 
|  | 203 | } | 
|  | 204 |  | 
|  | 205 | void suppressInstanceContext() { | 
|  | 206 | HasInstanceContext = false; | 
|  | 207 | } | 
|  | 208 |  | 
|  | 209 | const CXXRecordDecl *resolveInstanceContext(Sema &S) const { | 
|  | 210 | assert(HasInstanceContext); | 
|  | 211 | if (CalculatedInstanceContext) | 
|  | 212 | return InstanceContext; | 
|  | 213 |  | 
|  | 214 | CalculatedInstanceContext = true; | 
|  | 215 | DeclContext *IC = S.computeDeclContext(getBaseObjectType()); | 
| Craig Topper | c3ec149 | 2014-05-26 06:22:03 +0000 | [diff] [blame] | 216 | InstanceContext = (IC ? cast<CXXRecordDecl>(IC)->getCanonicalDecl() | 
|  | 217 | : nullptr); | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 218 | return InstanceContext; | 
|  | 219 | } | 
|  | 220 |  | 
|  | 221 | const CXXRecordDecl *getDeclaringClass() const { | 
|  | 222 | return DeclaringClass; | 
|  | 223 | } | 
|  | 224 |  | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 225 | /// The "effective" naming class is the canonical non-anonymous | 
|  | 226 | /// class containing the actual naming class. | 
|  | 227 | const CXXRecordDecl *getEffectiveNamingClass() const { | 
|  | 228 | const CXXRecordDecl *namingClass = getNamingClass(); | 
|  | 229 | while (namingClass->isAnonymousStructOrUnion()) | 
|  | 230 | namingClass = cast<CXXRecordDecl>(namingClass->getParent()); | 
|  | 231 | return namingClass->getCanonicalDecl(); | 
|  | 232 | } | 
|  | 233 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 234 | private: | 
|  | 235 | void initialize() { | 
|  | 236 | HasInstanceContext = (isMemberAccess() && | 
|  | 237 | !getBaseObjectType().isNull() && | 
|  | 238 | getTargetDecl()->isCXXInstanceMember()); | 
|  | 239 | CalculatedInstanceContext = false; | 
| Craig Topper | c3ec149 | 2014-05-26 06:22:03 +0000 | [diff] [blame] | 240 | InstanceContext = nullptr; | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 241 |  | 
|  | 242 | if (isMemberAccess()) | 
|  | 243 | DeclaringClass = FindDeclaringClass(getTargetDecl()); | 
|  | 244 | else | 
|  | 245 | DeclaringClass = getBaseClass(); | 
|  | 246 | DeclaringClass = DeclaringClass->getCanonicalDecl(); | 
|  | 247 | } | 
|  | 248 |  | 
|  | 249 | bool HasInstanceContext : 1; | 
|  | 250 | mutable bool CalculatedInstanceContext : 1; | 
|  | 251 | mutable const CXXRecordDecl *InstanceContext; | 
|  | 252 | const CXXRecordDecl *DeclaringClass; | 
|  | 253 | }; | 
|  | 254 |  | 
| Alexander Kornienko | ab9db51 | 2015-06-22 23:07:51 +0000 | [diff] [blame] | 255 | } | 
| John McCall | 553c079 | 2010-01-23 00:46:32 +0000 | [diff] [blame] | 256 |  | 
| John McCall | 9720514 | 2010-05-04 05:11:27 +0000 | [diff] [blame] | 257 | /// Checks whether one class might instantiate to the other. | 
|  | 258 | static bool MightInstantiateTo(const CXXRecordDecl *From, | 
|  | 259 | const CXXRecordDecl *To) { | 
|  | 260 | // Declaration names are always preserved by instantiation. | 
|  | 261 | if (From->getDeclName() != To->getDeclName()) | 
|  | 262 | return false; | 
|  | 263 |  | 
|  | 264 | const DeclContext *FromDC = From->getDeclContext()->getPrimaryContext(); | 
|  | 265 | const DeclContext *ToDC = To->getDeclContext()->getPrimaryContext(); | 
|  | 266 | if (FromDC == ToDC) return true; | 
|  | 267 | if (FromDC->isFileContext() || ToDC->isFileContext()) return false; | 
|  | 268 |  | 
|  | 269 | // Be conservative. | 
|  | 270 | return true; | 
|  | 271 | } | 
|  | 272 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 273 | /// Checks whether one class is derived from another, inclusively. | 
|  | 274 | /// Properly indicates when it couldn't be determined due to | 
|  | 275 | /// dependence. | 
|  | 276 | /// | 
|  | 277 | /// This should probably be donated to AST or at least Sema. | 
|  | 278 | static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived, | 
|  | 279 | const CXXRecordDecl *Target) { | 
|  | 280 | assert(Derived->getCanonicalDecl() == Derived); | 
|  | 281 | assert(Target->getCanonicalDecl() == Target); | 
| John McCall | 69f7586 | 2010-03-24 09:04:37 +0000 | [diff] [blame] | 282 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 283 | if (Derived == Target) return AR_accessible; | 
| John McCall | 69f7586 | 2010-03-24 09:04:37 +0000 | [diff] [blame] | 284 |  | 
| John McCall | 9720514 | 2010-05-04 05:11:27 +0000 | [diff] [blame] | 285 | bool CheckDependent = Derived->isDependentContext(); | 
|  | 286 | if (CheckDependent && MightInstantiateTo(Derived, Target)) | 
|  | 287 | return AR_dependent; | 
|  | 288 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 289 | AccessResult OnFailure = AR_inaccessible; | 
| Chris Lattner | 0e62c1c | 2011-07-23 10:55:15 +0000 | [diff] [blame] | 290 | SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 291 |  | 
|  | 292 | while (true) { | 
| Richard Smith | fd55fc8 | 2016-03-23 20:39:06 +0000 | [diff] [blame] | 293 | if (Derived->isDependentContext() && !Derived->hasDefinition() && | 
|  | 294 | !Derived->isLambda()) | 
| Douglas Gregor | 0201a4c | 2011-11-14 23:00:43 +0000 | [diff] [blame] | 295 | return AR_dependent; | 
| Richard Smith | fd55fc8 | 2016-03-23 20:39:06 +0000 | [diff] [blame] | 296 |  | 
| Aaron Ballman | 574705e | 2014-03-13 15:41:46 +0000 | [diff] [blame] | 297 | for (const auto &I : Derived->bases()) { | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 298 | const CXXRecordDecl *RD; | 
|  | 299 |  | 
| Aaron Ballman | 574705e | 2014-03-13 15:41:46 +0000 | [diff] [blame] | 300 | QualType T = I.getType(); | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 301 | if (const RecordType *RT = T->getAs<RecordType>()) { | 
|  | 302 | RD = cast<CXXRecordDecl>(RT->getDecl()); | 
| John McCall | 9720514 | 2010-05-04 05:11:27 +0000 | [diff] [blame] | 303 | } else if (const InjectedClassNameType *IT | 
|  | 304 | = T->getAs<InjectedClassNameType>()) { | 
|  | 305 | RD = IT->getDecl(); | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 306 | } else { | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 307 | assert(T->isDependentType() && "non-dependent base wasn't a record?"); | 
|  | 308 | OnFailure = AR_dependent; | 
|  | 309 | continue; | 
|  | 310 | } | 
|  | 311 |  | 
|  | 312 | RD = RD->getCanonicalDecl(); | 
|  | 313 | if (RD == Target) return AR_accessible; | 
| John McCall | 9720514 | 2010-05-04 05:11:27 +0000 | [diff] [blame] | 314 | if (CheckDependent && MightInstantiateTo(RD, Target)) | 
|  | 315 | OnFailure = AR_dependent; | 
|  | 316 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 317 | Queue.push_back(RD); | 
|  | 318 | } | 
|  | 319 |  | 
|  | 320 | if (Queue.empty()) break; | 
|  | 321 |  | 
| Robert Wilhelm | 25284cc | 2013-08-23 16:11:15 +0000 | [diff] [blame] | 322 | Derived = Queue.pop_back_val(); | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 323 | } | 
|  | 324 |  | 
|  | 325 | return OnFailure; | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 326 | } | 
|  | 327 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 328 |  | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 329 | static bool MightInstantiateTo(Sema &S, DeclContext *Context, | 
|  | 330 | DeclContext *Friend) { | 
|  | 331 | if (Friend == Context) | 
|  | 332 | return true; | 
|  | 333 |  | 
|  | 334 | assert(!Friend->isDependentContext() && | 
|  | 335 | "can't handle friends with dependent contexts here"); | 
|  | 336 |  | 
|  | 337 | if (!Context->isDependentContext()) | 
|  | 338 | return false; | 
|  | 339 |  | 
|  | 340 | if (Friend->isFileContext()) | 
|  | 341 | return false; | 
|  | 342 |  | 
|  | 343 | // TODO: this is very conservative | 
|  | 344 | return true; | 
|  | 345 | } | 
|  | 346 |  | 
|  | 347 | // Asks whether the type in 'context' can ever instantiate to the type | 
|  | 348 | // in 'friend'. | 
|  | 349 | static bool MightInstantiateTo(Sema &S, CanQualType Context, CanQualType Friend) { | 
|  | 350 | if (Friend == Context) | 
|  | 351 | return true; | 
|  | 352 |  | 
|  | 353 | if (!Friend->isDependentType() && !Context->isDependentType()) | 
|  | 354 | return false; | 
|  | 355 |  | 
|  | 356 | // TODO: this is very conservative. | 
|  | 357 | return true; | 
|  | 358 | } | 
|  | 359 |  | 
|  | 360 | static bool MightInstantiateTo(Sema &S, | 
|  | 361 | FunctionDecl *Context, | 
|  | 362 | FunctionDecl *Friend) { | 
|  | 363 | if (Context->getDeclName() != Friend->getDeclName()) | 
|  | 364 | return false; | 
|  | 365 |  | 
|  | 366 | if (!MightInstantiateTo(S, | 
|  | 367 | Context->getDeclContext(), | 
|  | 368 | Friend->getDeclContext())) | 
|  | 369 | return false; | 
|  | 370 |  | 
|  | 371 | CanQual<FunctionProtoType> FriendTy | 
|  | 372 | = S.Context.getCanonicalType(Friend->getType()) | 
|  | 373 | ->getAs<FunctionProtoType>(); | 
|  | 374 | CanQual<FunctionProtoType> ContextTy | 
|  | 375 | = S.Context.getCanonicalType(Context->getType()) | 
|  | 376 | ->getAs<FunctionProtoType>(); | 
|  | 377 |  | 
|  | 378 | // There isn't any way that I know of to add qualifiers | 
|  | 379 | // during instantiation. | 
|  | 380 | if (FriendTy.getQualifiers() != ContextTy.getQualifiers()) | 
|  | 381 | return false; | 
|  | 382 |  | 
| Alp Toker | 9cacbab | 2014-01-20 20:26:09 +0000 | [diff] [blame] | 383 | if (FriendTy->getNumParams() != ContextTy->getNumParams()) | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 384 | return false; | 
|  | 385 |  | 
| Alp Toker | 314cc81 | 2014-01-25 16:55:45 +0000 | [diff] [blame] | 386 | if (!MightInstantiateTo(S, ContextTy->getReturnType(), | 
|  | 387 | FriendTy->getReturnType())) | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 388 | return false; | 
|  | 389 |  | 
| Alp Toker | 9cacbab | 2014-01-20 20:26:09 +0000 | [diff] [blame] | 390 | for (unsigned I = 0, E = FriendTy->getNumParams(); I != E; ++I) | 
|  | 391 | if (!MightInstantiateTo(S, ContextTy->getParamType(I), | 
|  | 392 | FriendTy->getParamType(I))) | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 393 | return false; | 
|  | 394 |  | 
|  | 395 | return true; | 
|  | 396 | } | 
|  | 397 |  | 
|  | 398 | static bool MightInstantiateTo(Sema &S, | 
|  | 399 | FunctionTemplateDecl *Context, | 
|  | 400 | FunctionTemplateDecl *Friend) { | 
|  | 401 | return MightInstantiateTo(S, | 
|  | 402 | Context->getTemplatedDecl(), | 
|  | 403 | Friend->getTemplatedDecl()); | 
|  | 404 | } | 
|  | 405 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 406 | static AccessResult MatchesFriend(Sema &S, | 
|  | 407 | const EffectiveContext &EC, | 
|  | 408 | const CXXRecordDecl *Friend) { | 
| John McCall | 39e8288 | 2010-03-17 20:01:29 +0000 | [diff] [blame] | 409 | if (EC.includesClass(Friend)) | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 410 | return AR_accessible; | 
| John McCall | 39e8288 | 2010-03-17 20:01:29 +0000 | [diff] [blame] | 411 |  | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 412 | if (EC.isDependent()) { | 
| Richard Smith | fd55fc8 | 2016-03-23 20:39:06 +0000 | [diff] [blame] | 413 | for (const CXXRecordDecl *Context : EC.Records) { | 
|  | 414 | if (MightInstantiateTo(Context, Friend)) | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 415 | return AR_dependent; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 416 | } | 
|  | 417 | } | 
|  | 418 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 419 | return AR_inaccessible; | 
| John McCall | 39e8288 | 2010-03-17 20:01:29 +0000 | [diff] [blame] | 420 | } | 
|  | 421 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 422 | static AccessResult MatchesFriend(Sema &S, | 
|  | 423 | const EffectiveContext &EC, | 
|  | 424 | CanQualType Friend) { | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 425 | if (const RecordType *RT = Friend->getAs<RecordType>()) | 
|  | 426 | return MatchesFriend(S, EC, cast<CXXRecordDecl>(RT->getDecl())); | 
| John McCall | 39e8288 | 2010-03-17 20:01:29 +0000 | [diff] [blame] | 427 |  | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 428 | // TODO: we can do better than this | 
|  | 429 | if (Friend->isDependentType()) | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 430 | return AR_dependent; | 
| John McCall | 39e8288 | 2010-03-17 20:01:29 +0000 | [diff] [blame] | 431 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 432 | return AR_inaccessible; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 433 | } | 
|  | 434 |  | 
|  | 435 | /// Determines whether the given friend class template matches | 
|  | 436 | /// anything in the effective context. | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 437 | static AccessResult MatchesFriend(Sema &S, | 
|  | 438 | const EffectiveContext &EC, | 
|  | 439 | ClassTemplateDecl *Friend) { | 
|  | 440 | AccessResult OnFailure = AR_inaccessible; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 441 |  | 
| John McCall | 598b440 | 2010-03-25 06:39:04 +0000 | [diff] [blame] | 442 | // Check whether the friend is the template of a class in the | 
|  | 443 | // context chain. | 
| Chris Lattner | 0e62c1c | 2011-07-23 10:55:15 +0000 | [diff] [blame] | 444 | for (SmallVectorImpl<CXXRecordDecl*>::const_iterator | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 445 | I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { | 
|  | 446 | CXXRecordDecl *Record = *I; | 
|  | 447 |  | 
| John McCall | 598b440 | 2010-03-25 06:39:04 +0000 | [diff] [blame] | 448 | // Figure out whether the current class has a template: | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 449 | ClassTemplateDecl *CTD; | 
|  | 450 |  | 
|  | 451 | // A specialization of the template... | 
|  | 452 | if (isa<ClassTemplateSpecializationDecl>(Record)) { | 
|  | 453 | CTD = cast<ClassTemplateSpecializationDecl>(Record) | 
|  | 454 | ->getSpecializedTemplate(); | 
|  | 455 |  | 
|  | 456 | // ... or the template pattern itself. | 
|  | 457 | } else { | 
|  | 458 | CTD = Record->getDescribedClassTemplate(); | 
|  | 459 | if (!CTD) continue; | 
|  | 460 | } | 
|  | 461 |  | 
|  | 462 | // It's a match. | 
|  | 463 | if (Friend == CTD->getCanonicalDecl()) | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 464 | return AR_accessible; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 465 |  | 
| John McCall | 598b440 | 2010-03-25 06:39:04 +0000 | [diff] [blame] | 466 | // If the context isn't dependent, it can't be a dependent match. | 
|  | 467 | if (!EC.isDependent()) | 
|  | 468 | continue; | 
|  | 469 |  | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 470 | // If the template names don't match, it can't be a dependent | 
| Richard Smith | 3f1b5d0 | 2011-05-05 21:57:07 +0000 | [diff] [blame] | 471 | // match. | 
|  | 472 | if (CTD->getDeclName() != Friend->getDeclName()) | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 473 | continue; | 
|  | 474 |  | 
|  | 475 | // If the class's context can't instantiate to the friend's | 
|  | 476 | // context, it can't be a dependent match. | 
|  | 477 | if (!MightInstantiateTo(S, CTD->getDeclContext(), | 
|  | 478 | Friend->getDeclContext())) | 
|  | 479 | continue; | 
|  | 480 |  | 
|  | 481 | // Otherwise, it's a dependent match. | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 482 | OnFailure = AR_dependent; | 
| John McCall | 39e8288 | 2010-03-17 20:01:29 +0000 | [diff] [blame] | 483 | } | 
|  | 484 |  | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 485 | return OnFailure; | 
|  | 486 | } | 
|  | 487 |  | 
|  | 488 | /// Determines whether the given friend function matches anything in | 
|  | 489 | /// the effective context. | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 490 | static AccessResult MatchesFriend(Sema &S, | 
|  | 491 | const EffectiveContext &EC, | 
|  | 492 | FunctionDecl *Friend) { | 
|  | 493 | AccessResult OnFailure = AR_inaccessible; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 494 |  | 
| Chris Lattner | 0e62c1c | 2011-07-23 10:55:15 +0000 | [diff] [blame] | 495 | for (SmallVectorImpl<FunctionDecl*>::const_iterator | 
| John McCall | 3dc81f7 | 2010-03-27 06:55:49 +0000 | [diff] [blame] | 496 | I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { | 
|  | 497 | if (Friend == *I) | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 498 | return AR_accessible; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 499 |  | 
| John McCall | 3dc81f7 | 2010-03-27 06:55:49 +0000 | [diff] [blame] | 500 | if (EC.isDependent() && MightInstantiateTo(S, *I, Friend)) | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 501 | OnFailure = AR_dependent; | 
| John McCall | 3dc81f7 | 2010-03-27 06:55:49 +0000 | [diff] [blame] | 502 | } | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 503 |  | 
| John McCall | 3dc81f7 | 2010-03-27 06:55:49 +0000 | [diff] [blame] | 504 | return OnFailure; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 505 | } | 
|  | 506 |  | 
|  | 507 | /// Determines whether the given friend function template matches | 
|  | 508 | /// anything in the effective context. | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 509 | static AccessResult MatchesFriend(Sema &S, | 
|  | 510 | const EffectiveContext &EC, | 
|  | 511 | FunctionTemplateDecl *Friend) { | 
|  | 512 | if (EC.Functions.empty()) return AR_inaccessible; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 513 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 514 | AccessResult OnFailure = AR_inaccessible; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 515 |  | 
| Chris Lattner | 0e62c1c | 2011-07-23 10:55:15 +0000 | [diff] [blame] | 516 | for (SmallVectorImpl<FunctionDecl*>::const_iterator | 
| John McCall | 3dc81f7 | 2010-03-27 06:55:49 +0000 | [diff] [blame] | 517 | I = EC.Functions.begin(), E = EC.Functions.end(); I != E; ++I) { | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 518 |  | 
| John McCall | 3dc81f7 | 2010-03-27 06:55:49 +0000 | [diff] [blame] | 519 | FunctionTemplateDecl *FTD = (*I)->getPrimaryTemplate(); | 
|  | 520 | if (!FTD) | 
|  | 521 | FTD = (*I)->getDescribedFunctionTemplate(); | 
|  | 522 | if (!FTD) | 
|  | 523 | continue; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 524 |  | 
| John McCall | 3dc81f7 | 2010-03-27 06:55:49 +0000 | [diff] [blame] | 525 | FTD = FTD->getCanonicalDecl(); | 
|  | 526 |  | 
|  | 527 | if (Friend == FTD) | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 528 | return AR_accessible; | 
| John McCall | 3dc81f7 | 2010-03-27 06:55:49 +0000 | [diff] [blame] | 529 |  | 
|  | 530 | if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend)) | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 531 | OnFailure = AR_dependent; | 
| John McCall | 3dc81f7 | 2010-03-27 06:55:49 +0000 | [diff] [blame] | 532 | } | 
|  | 533 |  | 
|  | 534 | return OnFailure; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 535 | } | 
|  | 536 |  | 
|  | 537 | /// Determines whether the given friend declaration matches anything | 
|  | 538 | /// in the effective context. | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 539 | static AccessResult MatchesFriend(Sema &S, | 
|  | 540 | const EffectiveContext &EC, | 
|  | 541 | FriendDecl *FriendD) { | 
| John McCall | 2c2eb12 | 2010-10-16 06:59:13 +0000 | [diff] [blame] | 542 | // Whitelist accesses if there's an invalid or unsupported friend | 
|  | 543 | // declaration. | 
|  | 544 | if (FriendD->isInvalidDecl() || FriendD->isUnsupportedFriend()) | 
| John McCall | de3fd22 | 2010-10-12 23:13:28 +0000 | [diff] [blame] | 545 | return AR_accessible; | 
|  | 546 |  | 
| John McCall | 15ad096 | 2010-03-25 18:04:51 +0000 | [diff] [blame] | 547 | if (TypeSourceInfo *T = FriendD->getFriendType()) | 
|  | 548 | return MatchesFriend(S, EC, T->getType()->getCanonicalTypeUnqualified()); | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 549 |  | 
|  | 550 | NamedDecl *Friend | 
|  | 551 | = cast<NamedDecl>(FriendD->getFriendDecl()->getCanonicalDecl()); | 
| John McCall | 39e8288 | 2010-03-17 20:01:29 +0000 | [diff] [blame] | 552 |  | 
|  | 553 | // FIXME: declarations with dependent or templated scope. | 
|  | 554 |  | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 555 | if (isa<ClassTemplateDecl>(Friend)) | 
|  | 556 | return MatchesFriend(S, EC, cast<ClassTemplateDecl>(Friend)); | 
| John McCall | 39e8288 | 2010-03-17 20:01:29 +0000 | [diff] [blame] | 557 |  | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 558 | if (isa<FunctionTemplateDecl>(Friend)) | 
|  | 559 | return MatchesFriend(S, EC, cast<FunctionTemplateDecl>(Friend)); | 
| John McCall | 39e8288 | 2010-03-17 20:01:29 +0000 | [diff] [blame] | 560 |  | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 561 | if (isa<CXXRecordDecl>(Friend)) | 
|  | 562 | return MatchesFriend(S, EC, cast<CXXRecordDecl>(Friend)); | 
| John McCall | 39e8288 | 2010-03-17 20:01:29 +0000 | [diff] [blame] | 563 |  | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 564 | assert(isa<FunctionDecl>(Friend) && "unknown friend decl kind"); | 
|  | 565 | return MatchesFriend(S, EC, cast<FunctionDecl>(Friend)); | 
| John McCall | 39e8288 | 2010-03-17 20:01:29 +0000 | [diff] [blame] | 566 | } | 
|  | 567 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 568 | static AccessResult GetFriendKind(Sema &S, | 
|  | 569 | const EffectiveContext &EC, | 
|  | 570 | const CXXRecordDecl *Class) { | 
|  | 571 | AccessResult OnFailure = AR_inaccessible; | 
| John McCall | fb803d7 | 2010-03-17 04:58:56 +0000 | [diff] [blame] | 572 |  | 
| John McCall | 16927f6 | 2010-03-12 01:19:31 +0000 | [diff] [blame] | 573 | // Okay, check friends. | 
| Aaron Ballman | 522a6dd | 2014-03-13 17:00:06 +0000 | [diff] [blame] | 574 | for (auto *Friend : Class->friends()) { | 
| John McCall | 39e8288 | 2010-03-17 20:01:29 +0000 | [diff] [blame] | 575 | switch (MatchesFriend(S, EC, Friend)) { | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 576 | case AR_accessible: | 
|  | 577 | return AR_accessible; | 
| John McCall | 16927f6 | 2010-03-12 01:19:31 +0000 | [diff] [blame] | 578 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 579 | case AR_inaccessible: | 
|  | 580 | continue; | 
|  | 581 |  | 
|  | 582 | case AR_dependent: | 
|  | 583 | OnFailure = AR_dependent; | 
| John McCall | 39e8288 | 2010-03-17 20:01:29 +0000 | [diff] [blame] | 584 | break; | 
| John McCall | 16927f6 | 2010-03-12 01:19:31 +0000 | [diff] [blame] | 585 | } | 
| John McCall | 16927f6 | 2010-03-12 01:19:31 +0000 | [diff] [blame] | 586 | } | 
|  | 587 |  | 
|  | 588 | // That's it, give up. | 
| John McCall | fb803d7 | 2010-03-17 04:58:56 +0000 | [diff] [blame] | 589 | return OnFailure; | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 590 | } | 
|  | 591 |  | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 592 | namespace { | 
|  | 593 |  | 
|  | 594 | /// A helper class for checking for a friend which will grant access | 
|  | 595 | /// to a protected instance member. | 
|  | 596 | struct ProtectedFriendContext { | 
|  | 597 | Sema &S; | 
|  | 598 | const EffectiveContext &EC; | 
|  | 599 | const CXXRecordDecl *NamingClass; | 
|  | 600 | bool CheckDependent; | 
|  | 601 | bool EverDependent; | 
|  | 602 |  | 
|  | 603 | /// The path down to the current base class. | 
| Chris Lattner | 0e62c1c | 2011-07-23 10:55:15 +0000 | [diff] [blame] | 604 | SmallVector<const CXXRecordDecl*, 20> CurPath; | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 605 |  | 
|  | 606 | ProtectedFriendContext(Sema &S, const EffectiveContext &EC, | 
|  | 607 | const CXXRecordDecl *InstanceContext, | 
|  | 608 | const CXXRecordDecl *NamingClass) | 
|  | 609 | : S(S), EC(EC), NamingClass(NamingClass), | 
|  | 610 | CheckDependent(InstanceContext->isDependentContext() || | 
|  | 611 | NamingClass->isDependentContext()), | 
|  | 612 | EverDependent(false) {} | 
|  | 613 |  | 
| John McCall | 1177ff1 | 2010-08-28 08:47:21 +0000 | [diff] [blame] | 614 | /// Check classes in the current path for friendship, starting at | 
|  | 615 | /// the given index. | 
|  | 616 | bool checkFriendshipAlongPath(unsigned I) { | 
|  | 617 | assert(I < CurPath.size()); | 
|  | 618 | for (unsigned E = CurPath.size(); I != E; ++I) { | 
|  | 619 | switch (GetFriendKind(S, EC, CurPath[I])) { | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 620 | case AR_accessible:   return true; | 
|  | 621 | case AR_inaccessible: continue; | 
|  | 622 | case AR_dependent:    EverDependent = true; continue; | 
|  | 623 | } | 
|  | 624 | } | 
|  | 625 | return false; | 
|  | 626 | } | 
|  | 627 |  | 
|  | 628 | /// Perform a search starting at the given class. | 
| John McCall | 1177ff1 | 2010-08-28 08:47:21 +0000 | [diff] [blame] | 629 | /// | 
|  | 630 | /// PrivateDepth is the index of the last (least derived) class | 
|  | 631 | /// along the current path such that a notional public member of | 
|  | 632 | /// the final class in the path would have access in that class. | 
|  | 633 | bool findFriendship(const CXXRecordDecl *Cur, unsigned PrivateDepth) { | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 634 | // If we ever reach the naming class, check the current path for | 
|  | 635 | // friendship.  We can also stop recursing because we obviously | 
|  | 636 | // won't find the naming class there again. | 
| John McCall | 1177ff1 | 2010-08-28 08:47:21 +0000 | [diff] [blame] | 637 | if (Cur == NamingClass) | 
|  | 638 | return checkFriendshipAlongPath(PrivateDepth); | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 639 |  | 
|  | 640 | if (CheckDependent && MightInstantiateTo(Cur, NamingClass)) | 
|  | 641 | EverDependent = true; | 
|  | 642 |  | 
|  | 643 | // Recurse into the base classes. | 
| Aaron Ballman | 574705e | 2014-03-13 15:41:46 +0000 | [diff] [blame] | 644 | for (const auto &I : Cur->bases()) { | 
| John McCall | 1177ff1 | 2010-08-28 08:47:21 +0000 | [diff] [blame] | 645 | // If this is private inheritance, then a public member of the | 
|  | 646 | // base will not have any access in classes derived from Cur. | 
|  | 647 | unsigned BasePrivateDepth = PrivateDepth; | 
| Aaron Ballman | 574705e | 2014-03-13 15:41:46 +0000 | [diff] [blame] | 648 | if (I.getAccessSpecifier() == AS_private) | 
| John McCall | 1177ff1 | 2010-08-28 08:47:21 +0000 | [diff] [blame] | 649 | BasePrivateDepth = CurPath.size() - 1; | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 650 |  | 
|  | 651 | const CXXRecordDecl *RD; | 
|  | 652 |  | 
| Aaron Ballman | 574705e | 2014-03-13 15:41:46 +0000 | [diff] [blame] | 653 | QualType T = I.getType(); | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 654 | if (const RecordType *RT = T->getAs<RecordType>()) { | 
|  | 655 | RD = cast<CXXRecordDecl>(RT->getDecl()); | 
|  | 656 | } else if (const InjectedClassNameType *IT | 
|  | 657 | = T->getAs<InjectedClassNameType>()) { | 
|  | 658 | RD = IT->getDecl(); | 
|  | 659 | } else { | 
|  | 660 | assert(T->isDependentType() && "non-dependent base wasn't a record?"); | 
|  | 661 | EverDependent = true; | 
|  | 662 | continue; | 
|  | 663 | } | 
|  | 664 |  | 
|  | 665 | // Recurse.  We don't need to clean up if this returns true. | 
| John McCall | 1177ff1 | 2010-08-28 08:47:21 +0000 | [diff] [blame] | 666 | CurPath.push_back(RD); | 
|  | 667 | if (findFriendship(RD->getCanonicalDecl(), BasePrivateDepth)) | 
|  | 668 | return true; | 
|  | 669 | CurPath.pop_back(); | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 670 | } | 
|  | 671 |  | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 672 | return false; | 
|  | 673 | } | 
| John McCall | 1177ff1 | 2010-08-28 08:47:21 +0000 | [diff] [blame] | 674 |  | 
|  | 675 | bool findFriendship(const CXXRecordDecl *Cur) { | 
|  | 676 | assert(CurPath.empty()); | 
|  | 677 | CurPath.push_back(Cur); | 
|  | 678 | return findFriendship(Cur, 0); | 
|  | 679 | } | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 680 | }; | 
| Alexander Kornienko | ab9db51 | 2015-06-22 23:07:51 +0000 | [diff] [blame] | 681 | } | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 682 |  | 
|  | 683 | /// Search for a class P that EC is a friend of, under the constraint | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 684 | ///   InstanceContext <= P | 
|  | 685 | /// if InstanceContext exists, or else | 
|  | 686 | ///   NamingClass <= P | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 687 | /// and with the additional restriction that a protected member of | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 688 | /// NamingClass would have some natural access in P, which implicitly | 
|  | 689 | /// imposes the constraint that P <= NamingClass. | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 690 | /// | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 691 | /// This isn't quite the condition laid out in the standard. | 
|  | 692 | /// Instead of saying that a notional protected member of NamingClass | 
|  | 693 | /// would have to have some natural access in P, it says the actual | 
|  | 694 | /// target has to have some natural access in P, which opens up the | 
|  | 695 | /// possibility that the target (which is not necessarily a member | 
|  | 696 | /// of NamingClass) might be more accessible along some path not | 
|  | 697 | /// passing through it.  That's really a bad idea, though, because it | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 698 | /// introduces two problems: | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 699 | ///   - Most importantly, it breaks encapsulation because you can | 
|  | 700 | ///     access a forbidden base class's members by directly subclassing | 
|  | 701 | ///     it elsewhere. | 
|  | 702 | ///   - It also makes access substantially harder to compute because it | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 703 | ///     breaks the hill-climbing algorithm: knowing that the target is | 
|  | 704 | ///     accessible in some base class would no longer let you change | 
|  | 705 | ///     the question solely to whether the base class is accessible, | 
|  | 706 | ///     because the original target might have been more accessible | 
|  | 707 | ///     because of crazy subclassing. | 
|  | 708 | /// So we don't implement that. | 
|  | 709 | static AccessResult GetProtectedFriendKind(Sema &S, const EffectiveContext &EC, | 
|  | 710 | const CXXRecordDecl *InstanceContext, | 
|  | 711 | const CXXRecordDecl *NamingClass) { | 
| Craig Topper | c3ec149 | 2014-05-26 06:22:03 +0000 | [diff] [blame] | 712 | assert(InstanceContext == nullptr || | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 713 | InstanceContext->getCanonicalDecl() == InstanceContext); | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 714 | assert(NamingClass->getCanonicalDecl() == NamingClass); | 
|  | 715 |  | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 716 | // If we don't have an instance context, our constraints give us | 
|  | 717 | // that NamingClass <= P <= NamingClass, i.e. P == NamingClass. | 
|  | 718 | // This is just the usual friendship check. | 
|  | 719 | if (!InstanceContext) return GetFriendKind(S, EC, NamingClass); | 
|  | 720 |  | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 721 | ProtectedFriendContext PRC(S, EC, InstanceContext, NamingClass); | 
|  | 722 | if (PRC.findFriendship(InstanceContext)) return AR_accessible; | 
|  | 723 | if (PRC.EverDependent) return AR_dependent; | 
|  | 724 | return AR_inaccessible; | 
|  | 725 | } | 
|  | 726 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 727 | static AccessResult HasAccess(Sema &S, | 
|  | 728 | const EffectiveContext &EC, | 
|  | 729 | const CXXRecordDecl *NamingClass, | 
|  | 730 | AccessSpecifier Access, | 
|  | 731 | const AccessTarget &Target) { | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 732 | assert(NamingClass->getCanonicalDecl() == NamingClass && | 
|  | 733 | "declaration should be canonicalized before being passed here"); | 
|  | 734 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 735 | if (Access == AS_public) return AR_accessible; | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 736 | assert(Access == AS_private || Access == AS_protected); | 
|  | 737 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 738 | AccessResult OnFailure = AR_inaccessible; | 
|  | 739 |  | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 740 | for (EffectiveContext::record_iterator | 
|  | 741 | I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { | 
|  | 742 | // All the declarations in EC have been canonicalized, so pointer | 
|  | 743 | // equality from this point on will work fine. | 
|  | 744 | const CXXRecordDecl *ECRecord = *I; | 
|  | 745 |  | 
|  | 746 | // [B2] and [M2] | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 747 | if (Access == AS_private) { | 
|  | 748 | if (ECRecord == NamingClass) | 
|  | 749 | return AR_accessible; | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 750 |  | 
| John McCall | 9720514 | 2010-05-04 05:11:27 +0000 | [diff] [blame] | 751 | if (EC.isDependent() && MightInstantiateTo(ECRecord, NamingClass)) | 
|  | 752 | OnFailure = AR_dependent; | 
|  | 753 |  | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 754 | // [B3] and [M3] | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 755 | } else { | 
|  | 756 | assert(Access == AS_protected); | 
|  | 757 | switch (IsDerivedFromInclusive(ECRecord, NamingClass)) { | 
|  | 758 | case AR_accessible: break; | 
|  | 759 | case AR_inaccessible: continue; | 
|  | 760 | case AR_dependent: OnFailure = AR_dependent; continue; | 
|  | 761 | } | 
|  | 762 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 763 | // C++ [class.protected]p1: | 
|  | 764 | //   An additional access check beyond those described earlier in | 
|  | 765 | //   [class.access] is applied when a non-static data member or | 
|  | 766 | //   non-static member function is a protected member of its naming | 
|  | 767 | //   class.  As described earlier, access to a protected member is | 
|  | 768 | //   granted because the reference occurs in a friend or member of | 
|  | 769 | //   some class C.  If the access is to form a pointer to member, | 
|  | 770 | //   the nested-name-specifier shall name C or a class derived from | 
|  | 771 | //   C. All other accesses involve a (possibly implicit) object | 
|  | 772 | //   expression. In this case, the class of the object expression | 
|  | 773 | //   shall be C or a class derived from C. | 
|  | 774 | // | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 775 | // We interpret this as a restriction on [M3]. | 
|  | 776 |  | 
|  | 777 | // In this part of the code, 'C' is just our context class ECRecord. | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 778 |  | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 779 | // These rules are different if we don't have an instance context. | 
|  | 780 | if (!Target.hasInstanceContext()) { | 
|  | 781 | // If it's not an instance member, these restrictions don't apply. | 
|  | 782 | if (!Target.isInstanceMember()) return AR_accessible; | 
|  | 783 |  | 
|  | 784 | // If it's an instance member, use the pointer-to-member rule | 
|  | 785 | // that the naming class has to be derived from the effective | 
|  | 786 | // context. | 
|  | 787 |  | 
| Francois Pichet | a39371c | 2012-04-17 12:35:05 +0000 | [diff] [blame] | 788 | // Emulate a MSVC bug where the creation of pointer-to-member | 
|  | 789 | // to protected member of base class is allowed but only from | 
| Francois Pichet | 52d3898 | 2012-04-19 07:48:57 +0000 | [diff] [blame] | 790 | // static member functions. | 
| Alp Toker | bfa3934 | 2014-01-14 12:51:41 +0000 | [diff] [blame] | 791 | if (S.getLangOpts().MSVCCompat && !EC.Functions.empty()) | 
| Francois Pichet | 5b061f0 | 2012-04-18 03:24:38 +0000 | [diff] [blame] | 792 | if (CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(EC.Functions.front())) | 
|  | 793 | if (MD->isStatic()) return AR_accessible; | 
| Francois Pichet | a39371c | 2012-04-17 12:35:05 +0000 | [diff] [blame] | 794 |  | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 795 | // Despite the standard's confident wording, there is a case | 
|  | 796 | // where you can have an instance member that's neither in a | 
|  | 797 | // pointer-to-member expression nor in a member access:  when | 
|  | 798 | // it names a field in an unevaluated context that can't be an | 
|  | 799 | // implicit member.  Pending clarification, we just apply the | 
|  | 800 | // same naming-class restriction here. | 
|  | 801 | //   FIXME: we're probably not correctly adding the | 
|  | 802 | //   protected-member restriction when we retroactively convert | 
|  | 803 | //   an expression to being evaluated. | 
|  | 804 |  | 
|  | 805 | // We know that ECRecord derives from NamingClass.  The | 
|  | 806 | // restriction says to check whether NamingClass derives from | 
|  | 807 | // ECRecord, but that's not really necessary: two distinct | 
|  | 808 | // classes can't be recursively derived from each other.  So | 
|  | 809 | // along this path, we just need to check whether the classes | 
|  | 810 | // are equal. | 
|  | 811 | if (NamingClass == ECRecord) return AR_accessible; | 
|  | 812 |  | 
|  | 813 | // Otherwise, this context class tells us nothing;  on to the next. | 
|  | 814 | continue; | 
|  | 815 | } | 
|  | 816 |  | 
|  | 817 | assert(Target.isInstanceMember()); | 
|  | 818 |  | 
|  | 819 | const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); | 
|  | 820 | if (!InstanceContext) { | 
|  | 821 | OnFailure = AR_dependent; | 
|  | 822 | continue; | 
|  | 823 | } | 
|  | 824 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 825 | switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) { | 
|  | 826 | case AR_accessible: return AR_accessible; | 
|  | 827 | case AR_inaccessible: continue; | 
|  | 828 | case AR_dependent: OnFailure = AR_dependent; continue; | 
|  | 829 | } | 
|  | 830 | } | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 831 | } | 
|  | 832 |  | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 833 | // [M3] and [B3] say that, if the target is protected in N, we grant | 
|  | 834 | // access if the access occurs in a friend or member of some class P | 
|  | 835 | // that's a subclass of N and where the target has some natural | 
|  | 836 | // access in P.  The 'member' aspect is easy to handle because P | 
|  | 837 | // would necessarily be one of the effective-context records, and we | 
|  | 838 | // address that above.  The 'friend' aspect is completely ridiculous | 
|  | 839 | // to implement because there are no restrictions at all on P | 
|  | 840 | // *unless* the [class.protected] restriction applies.  If it does, | 
|  | 841 | // however, we should ignore whether the naming class is a friend, | 
|  | 842 | // and instead rely on whether any potential P is a friend. | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 843 | if (Access == AS_protected && Target.isInstanceMember()) { | 
|  | 844 | // Compute the instance context if possible. | 
| Craig Topper | c3ec149 | 2014-05-26 06:22:03 +0000 | [diff] [blame] | 845 | const CXXRecordDecl *InstanceContext = nullptr; | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 846 | if (Target.hasInstanceContext()) { | 
|  | 847 | InstanceContext = Target.resolveInstanceContext(S); | 
|  | 848 | if (!InstanceContext) return AR_dependent; | 
|  | 849 | } | 
|  | 850 |  | 
| John McCall | 9632967 | 2010-08-28 07:56:00 +0000 | [diff] [blame] | 851 | switch (GetProtectedFriendKind(S, EC, InstanceContext, NamingClass)) { | 
|  | 852 | case AR_accessible: return AR_accessible; | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 853 | case AR_inaccessible: return OnFailure; | 
|  | 854 | case AR_dependent: return AR_dependent; | 
|  | 855 | } | 
| John McCall | c6af8f4 | 2010-08-28 08:10:32 +0000 | [diff] [blame] | 856 | llvm_unreachable("impossible friendship kind"); | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 857 | } | 
|  | 858 |  | 
|  | 859 | switch (GetFriendKind(S, EC, NamingClass)) { | 
|  | 860 | case AR_accessible: return AR_accessible; | 
|  | 861 | case AR_inaccessible: return OnFailure; | 
|  | 862 | case AR_dependent: return AR_dependent; | 
|  | 863 | } | 
|  | 864 |  | 
|  | 865 | // Silence bogus warnings | 
|  | 866 | llvm_unreachable("impossible friendship kind"); | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 867 | } | 
|  | 868 |  | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 869 | /// Finds the best path from the naming class to the declaring class, | 
|  | 870 | /// taking friend declarations into account. | 
|  | 871 | /// | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 872 | /// C++0x [class.access.base]p5: | 
|  | 873 | ///   A member m is accessible at the point R when named in class N if | 
|  | 874 | ///   [M1] m as a member of N is public, or | 
|  | 875 | ///   [M2] m as a member of N is private, and R occurs in a member or | 
|  | 876 | ///        friend of class N, or | 
|  | 877 | ///   [M3] m as a member of N is protected, and R occurs in a member or | 
|  | 878 | ///        friend of class N, or in a member or friend of a class P | 
|  | 879 | ///        derived from N, where m as a member of P is public, private, | 
|  | 880 | ///        or protected, or | 
|  | 881 | ///   [M4] there exists a base class B of N that is accessible at R, and | 
|  | 882 | ///        m is accessible at R when named in class B. | 
|  | 883 | /// | 
|  | 884 | /// C++0x [class.access.base]p4: | 
|  | 885 | ///   A base class B of N is accessible at R, if | 
|  | 886 | ///   [B1] an invented public member of B would be a public member of N, or | 
|  | 887 | ///   [B2] R occurs in a member or friend of class N, and an invented public | 
|  | 888 | ///        member of B would be a private or protected member of N, or | 
|  | 889 | ///   [B3] R occurs in a member or friend of a class P derived from N, and an | 
|  | 890 | ///        invented public member of B would be a private or protected member | 
|  | 891 | ///        of P, or | 
|  | 892 | ///   [B4] there exists a class S such that B is a base class of S accessible | 
|  | 893 | ///        at R and S is a base class of N accessible at R. | 
|  | 894 | /// | 
|  | 895 | /// Along a single inheritance path we can restate both of these | 
|  | 896 | /// iteratively: | 
|  | 897 | /// | 
|  | 898 | /// First, we note that M1-4 are equivalent to B1-4 if the member is | 
|  | 899 | /// treated as a notional base of its declaring class with inheritance | 
|  | 900 | /// access equivalent to the member's access.  Therefore we need only | 
|  | 901 | /// ask whether a class B is accessible from a class N in context R. | 
|  | 902 | /// | 
|  | 903 | /// Let B_1 .. B_n be the inheritance path in question (i.e. where | 
|  | 904 | /// B_1 = N, B_n = B, and for all i, B_{i+1} is a direct base class of | 
|  | 905 | /// B_i).  For i in 1..n, we will calculate ACAB(i), the access to the | 
|  | 906 | /// closest accessible base in the path: | 
|  | 907 | ///   Access(a, b) = (* access on the base specifier from a to b *) | 
|  | 908 | ///   Merge(a, forbidden) = forbidden | 
|  | 909 | ///   Merge(a, private) = forbidden | 
|  | 910 | ///   Merge(a, b) = min(a,b) | 
|  | 911 | ///   Accessible(c, forbidden) = false | 
|  | 912 | ///   Accessible(c, private) = (R is c) || IsFriend(c, R) | 
|  | 913 | ///   Accessible(c, protected) = (R derived from c) || IsFriend(c, R) | 
|  | 914 | ///   Accessible(c, public) = true | 
|  | 915 | ///   ACAB(n) = public | 
|  | 916 | ///   ACAB(i) = | 
|  | 917 | ///     let AccessToBase = Merge(Access(B_i, B_{i+1}), ACAB(i+1)) in | 
|  | 918 | ///     if Accessible(B_i, AccessToBase) then public else AccessToBase | 
|  | 919 | /// | 
| Sylvestre Ledru | 33b5baf | 2012-09-27 10:16:10 +0000 | [diff] [blame] | 920 | /// B is an accessible base of N at R iff ACAB(1) = public. | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 921 | /// | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 922 | /// \param FinalAccess the access of the "final step", or AS_public if | 
| John McCall | a332b95 | 2010-03-18 23:49:19 +0000 | [diff] [blame] | 923 | ///   there is no final step. | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 924 | /// \return null if friendship is dependent | 
|  | 925 | static CXXBasePath *FindBestPath(Sema &S, | 
|  | 926 | const EffectiveContext &EC, | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 927 | AccessTarget &Target, | 
| John McCall | a332b95 | 2010-03-18 23:49:19 +0000 | [diff] [blame] | 928 | AccessSpecifier FinalAccess, | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 929 | CXXBasePaths &Paths) { | 
|  | 930 | // Derive the paths to the desired base. | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 931 | const CXXRecordDecl *Derived = Target.getNamingClass(); | 
|  | 932 | const CXXRecordDecl *Base = Target.getDeclaringClass(); | 
|  | 933 |  | 
|  | 934 | // FIXME: fail correctly when there are dependent paths. | 
|  | 935 | bool isDerived = Derived->isDerivedFrom(const_cast<CXXRecordDecl*>(Base), | 
|  | 936 | Paths); | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 937 | assert(isDerived && "derived class not actually derived from base"); | 
|  | 938 | (void) isDerived; | 
|  | 939 |  | 
| Craig Topper | c3ec149 | 2014-05-26 06:22:03 +0000 | [diff] [blame] | 940 | CXXBasePath *BestPath = nullptr; | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 941 |  | 
| John McCall | a332b95 | 2010-03-18 23:49:19 +0000 | [diff] [blame] | 942 | assert(FinalAccess != AS_none && "forbidden access after declaring class"); | 
|  | 943 |  | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 944 | bool AnyDependent = false; | 
|  | 945 |  | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 946 | // Derive the friend-modified access along each path. | 
|  | 947 | for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); | 
|  | 948 | PI != PE; ++PI) { | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 949 | AccessTarget::SavedInstanceContext _ = Target.saveInstanceContext(); | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 950 |  | 
|  | 951 | // Walk through the path backwards. | 
| John McCall | a332b95 | 2010-03-18 23:49:19 +0000 | [diff] [blame] | 952 | AccessSpecifier PathAccess = FinalAccess; | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 953 | CXXBasePath::iterator I = PI->end(), E = PI->begin(); | 
|  | 954 | while (I != E) { | 
|  | 955 | --I; | 
|  | 956 |  | 
| John McCall | a332b95 | 2010-03-18 23:49:19 +0000 | [diff] [blame] | 957 | assert(PathAccess != AS_none); | 
|  | 958 |  | 
|  | 959 | // If the declaration is a private member of a base class, there | 
|  | 960 | // is no level of friendship in derived classes that can make it | 
|  | 961 | // accessible. | 
|  | 962 | if (PathAccess == AS_private) { | 
|  | 963 | PathAccess = AS_none; | 
|  | 964 | break; | 
|  | 965 | } | 
|  | 966 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 967 | const CXXRecordDecl *NC = I->Class->getCanonicalDecl(); | 
|  | 968 |  | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 969 | AccessSpecifier BaseAccess = I->Base->getAccessSpecifier(); | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 970 | PathAccess = std::max(PathAccess, BaseAccess); | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 971 |  | 
|  | 972 | switch (HasAccess(S, EC, NC, PathAccess, Target)) { | 
|  | 973 | case AR_inaccessible: break; | 
|  | 974 | case AR_accessible: | 
|  | 975 | PathAccess = AS_public; | 
|  | 976 |  | 
|  | 977 | // Future tests are not against members and so do not have | 
|  | 978 | // instance context. | 
|  | 979 | Target.suppressInstanceContext(); | 
|  | 980 | break; | 
|  | 981 | case AR_dependent: | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 982 | AnyDependent = true; | 
|  | 983 | goto Next; | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 984 | } | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 985 | } | 
|  | 986 |  | 
|  | 987 | // Note that we modify the path's Access field to the | 
|  | 988 | // friend-modified access. | 
| Craig Topper | c3ec149 | 2014-05-26 06:22:03 +0000 | [diff] [blame] | 989 | if (BestPath == nullptr || PathAccess < BestPath->Access) { | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 990 | BestPath = &*PI; | 
|  | 991 | BestPath->Access = PathAccess; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 992 |  | 
|  | 993 | // Short-circuit if we found a public path. | 
|  | 994 | if (BestPath->Access == AS_public) | 
|  | 995 | return BestPath; | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 996 | } | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 997 |  | 
|  | 998 | Next: ; | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 999 | } | 
|  | 1000 |  | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 1001 | assert((!BestPath || BestPath->Access != AS_public) && | 
|  | 1002 | "fell out of loop with public path"); | 
|  | 1003 |  | 
|  | 1004 | // We didn't find a public path, but at least one path was subject | 
|  | 1005 | // to dependent friendship, so delay the check. | 
|  | 1006 | if (AnyDependent) | 
| Craig Topper | c3ec149 | 2014-05-26 06:22:03 +0000 | [diff] [blame] | 1007 | return nullptr; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 1008 |  | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1009 | return BestPath; | 
|  | 1010 | } | 
|  | 1011 |  | 
| John McCall | 417e744 | 2010-09-03 04:56:05 +0000 | [diff] [blame] | 1012 | /// Given that an entity has protected natural access, check whether | 
|  | 1013 | /// access might be denied because of the protected member access | 
|  | 1014 | /// restriction. | 
|  | 1015 | /// | 
|  | 1016 | /// \return true if a note was emitted | 
|  | 1017 | static bool TryDiagnoseProtectedAccess(Sema &S, const EffectiveContext &EC, | 
|  | 1018 | AccessTarget &Target) { | 
|  | 1019 | // Only applies to instance accesses. | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1020 | if (!Target.isInstanceMember()) | 
| John McCall | 417e744 | 2010-09-03 04:56:05 +0000 | [diff] [blame] | 1021 | return false; | 
| John McCall | 417e744 | 2010-09-03 04:56:05 +0000 | [diff] [blame] | 1022 |  | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1023 | assert(Target.isMemberAccess()); | 
|  | 1024 |  | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1025 | const CXXRecordDecl *NamingClass = Target.getEffectiveNamingClass(); | 
| John McCall | 417e744 | 2010-09-03 04:56:05 +0000 | [diff] [blame] | 1026 |  | 
|  | 1027 | for (EffectiveContext::record_iterator | 
|  | 1028 | I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { | 
|  | 1029 | const CXXRecordDecl *ECRecord = *I; | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1030 | switch (IsDerivedFromInclusive(ECRecord, NamingClass)) { | 
| John McCall | 417e744 | 2010-09-03 04:56:05 +0000 | [diff] [blame] | 1031 | case AR_accessible: break; | 
|  | 1032 | case AR_inaccessible: continue; | 
|  | 1033 | case AR_dependent: continue; | 
|  | 1034 | } | 
|  | 1035 |  | 
|  | 1036 | // The effective context is a subclass of the declaring class. | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1037 | // Check whether the [class.protected] restriction is limiting | 
|  | 1038 | // access. | 
| John McCall | 417e744 | 2010-09-03 04:56:05 +0000 | [diff] [blame] | 1039 |  | 
|  | 1040 | // To get this exactly right, this might need to be checked more | 
|  | 1041 | // holistically;  it's not necessarily the case that gaining | 
|  | 1042 | // access here would grant us access overall. | 
|  | 1043 |  | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1044 | NamedDecl *D = Target.getTargetDecl(); | 
|  | 1045 |  | 
|  | 1046 | // If we don't have an instance context, [class.protected] says the | 
|  | 1047 | // naming class has to equal the context class. | 
|  | 1048 | if (!Target.hasInstanceContext()) { | 
|  | 1049 | // If it does, the restriction doesn't apply. | 
|  | 1050 | if (NamingClass == ECRecord) continue; | 
|  | 1051 |  | 
|  | 1052 | // TODO: it would be great to have a fixit here, since this is | 
|  | 1053 | // such an obvious error. | 
|  | 1054 | S.Diag(D->getLocation(), diag::note_access_protected_restricted_noobject) | 
|  | 1055 | << S.Context.getTypeDeclType(ECRecord); | 
|  | 1056 | return true; | 
|  | 1057 | } | 
|  | 1058 |  | 
| John McCall | 417e744 | 2010-09-03 04:56:05 +0000 | [diff] [blame] | 1059 | const CXXRecordDecl *InstanceContext = Target.resolveInstanceContext(S); | 
|  | 1060 | assert(InstanceContext && "diagnosing dependent access"); | 
|  | 1061 |  | 
|  | 1062 | switch (IsDerivedFromInclusive(InstanceContext, ECRecord)) { | 
|  | 1063 | case AR_accessible: continue; | 
|  | 1064 | case AR_dependent: continue; | 
|  | 1065 | case AR_inaccessible: | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1066 | break; | 
|  | 1067 | } | 
|  | 1068 |  | 
|  | 1069 | // Okay, the restriction seems to be what's limiting us. | 
|  | 1070 |  | 
|  | 1071 | // Use a special diagnostic for constructors and destructors. | 
|  | 1072 | if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D) || | 
|  | 1073 | (isa<FunctionTemplateDecl>(D) && | 
|  | 1074 | isa<CXXConstructorDecl>( | 
|  | 1075 | cast<FunctionTemplateDecl>(D)->getTemplatedDecl()))) { | 
| Alp Toker | a2794f9 | 2014-01-22 07:29:52 +0000 | [diff] [blame] | 1076 | return S.Diag(D->getLocation(), | 
|  | 1077 | diag::note_access_protected_restricted_ctordtor) | 
|  | 1078 | << isa<CXXDestructorDecl>(D->getAsFunction()); | 
| John McCall | 417e744 | 2010-09-03 04:56:05 +0000 | [diff] [blame] | 1079 | } | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1080 |  | 
|  | 1081 | // Otherwise, use the generic diagnostic. | 
| Alp Toker | a2794f9 | 2014-01-22 07:29:52 +0000 | [diff] [blame] | 1082 | return S.Diag(D->getLocation(), | 
|  | 1083 | diag::note_access_protected_restricted_object) | 
|  | 1084 | << S.Context.getTypeDeclType(ECRecord); | 
| John McCall | 417e744 | 2010-09-03 04:56:05 +0000 | [diff] [blame] | 1085 | } | 
|  | 1086 |  | 
|  | 1087 | return false; | 
|  | 1088 | } | 
|  | 1089 |  | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1090 | /// We are unable to access a given declaration due to its direct | 
|  | 1091 | /// access control;  diagnose that. | 
|  | 1092 | static void diagnoseBadDirectAccess(Sema &S, | 
|  | 1093 | const EffectiveContext &EC, | 
|  | 1094 | AccessTarget &entity) { | 
|  | 1095 | assert(entity.isMemberAccess()); | 
|  | 1096 | NamedDecl *D = entity.getTargetDecl(); | 
|  | 1097 |  | 
|  | 1098 | if (D->getAccess() == AS_protected && | 
|  | 1099 | TryDiagnoseProtectedAccess(S, EC, entity)) | 
|  | 1100 | return; | 
|  | 1101 |  | 
|  | 1102 | // Find an original declaration. | 
|  | 1103 | while (D->isOutOfLine()) { | 
| Craig Topper | c3ec149 | 2014-05-26 06:22:03 +0000 | [diff] [blame] | 1104 | NamedDecl *PrevDecl = nullptr; | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1105 | if (VarDecl *VD = dyn_cast<VarDecl>(D)) | 
|  | 1106 | PrevDecl = VD->getPreviousDecl(); | 
|  | 1107 | else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) | 
|  | 1108 | PrevDecl = FD->getPreviousDecl(); | 
|  | 1109 | else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D)) | 
|  | 1110 | PrevDecl = TND->getPreviousDecl(); | 
|  | 1111 | else if (TagDecl *TD = dyn_cast<TagDecl>(D)) { | 
|  | 1112 | if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName()) | 
|  | 1113 | break; | 
|  | 1114 | PrevDecl = TD->getPreviousDecl(); | 
|  | 1115 | } | 
|  | 1116 | if (!PrevDecl) break; | 
|  | 1117 | D = PrevDecl; | 
|  | 1118 | } | 
|  | 1119 |  | 
|  | 1120 | CXXRecordDecl *DeclaringClass = FindDeclaringClass(D); | 
|  | 1121 | Decl *ImmediateChild; | 
|  | 1122 | if (D->getDeclContext() == DeclaringClass) | 
|  | 1123 | ImmediateChild = D; | 
|  | 1124 | else { | 
|  | 1125 | DeclContext *DC = D->getDeclContext(); | 
|  | 1126 | while (DC->getParent() != DeclaringClass) | 
|  | 1127 | DC = DC->getParent(); | 
|  | 1128 | ImmediateChild = cast<Decl>(DC); | 
|  | 1129 | } | 
|  | 1130 |  | 
|  | 1131 | // Check whether there's an AccessSpecDecl preceding this in the | 
|  | 1132 | // chain of the DeclContext. | 
|  | 1133 | bool isImplicit = true; | 
| Aaron Ballman | 629afae | 2014-03-07 19:56:05 +0000 | [diff] [blame] | 1134 | for (const auto *I : DeclaringClass->decls()) { | 
|  | 1135 | if (I == ImmediateChild) break; | 
|  | 1136 | if (isa<AccessSpecDecl>(I)) { | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1137 | isImplicit = false; | 
|  | 1138 | break; | 
|  | 1139 | } | 
|  | 1140 | } | 
|  | 1141 |  | 
|  | 1142 | S.Diag(D->getLocation(), diag::note_access_natural) | 
|  | 1143 | << (unsigned) (D->getAccess() == AS_protected) | 
|  | 1144 | << isImplicit; | 
|  | 1145 | } | 
|  | 1146 |  | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1147 | /// Diagnose the path which caused the given declaration or base class | 
|  | 1148 | /// to become inaccessible. | 
|  | 1149 | static void DiagnoseAccessPath(Sema &S, | 
|  | 1150 | const EffectiveContext &EC, | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1151 | AccessTarget &entity) { | 
|  | 1152 | // Save the instance context to preserve invariants. | 
|  | 1153 | AccessTarget::SavedInstanceContext _ = entity.saveInstanceContext(); | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1154 |  | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1155 | // This basically repeats the main algorithm but keeps some more | 
|  | 1156 | // information. | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1157 |  | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1158 | // The natural access so far. | 
|  | 1159 | AccessSpecifier accessSoFar = AS_public; | 
| John McCall | 417e744 | 2010-09-03 04:56:05 +0000 | [diff] [blame] | 1160 |  | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1161 | // Check whether we have special rights to the declaring class. | 
|  | 1162 | if (entity.isMemberAccess()) { | 
|  | 1163 | NamedDecl *D = entity.getTargetDecl(); | 
|  | 1164 | accessSoFar = D->getAccess(); | 
|  | 1165 | const CXXRecordDecl *declaringClass = entity.getDeclaringClass(); | 
| John McCall | f551aca | 2010-10-20 08:15:06 +0000 | [diff] [blame] | 1166 |  | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1167 | switch (HasAccess(S, EC, declaringClass, accessSoFar, entity)) { | 
|  | 1168 | // If the declaration is accessible when named in its declaring | 
|  | 1169 | // class, then we must be constrained by the path. | 
|  | 1170 | case AR_accessible: | 
|  | 1171 | accessSoFar = AS_public; | 
|  | 1172 | entity.suppressInstanceContext(); | 
|  | 1173 | break; | 
| John McCall | f551aca | 2010-10-20 08:15:06 +0000 | [diff] [blame] | 1174 |  | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1175 | case AR_inaccessible: | 
|  | 1176 | if (accessSoFar == AS_private || | 
|  | 1177 | declaringClass == entity.getEffectiveNamingClass()) | 
|  | 1178 | return diagnoseBadDirectAccess(S, EC, entity); | 
|  | 1179 | break; | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1180 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1181 | case AR_dependent: | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1182 | llvm_unreachable("cannot diagnose dependent access"); | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1183 | } | 
|  | 1184 | } | 
|  | 1185 |  | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1186 | CXXBasePaths paths; | 
|  | 1187 | CXXBasePath &path = *FindBestPath(S, EC, entity, accessSoFar, paths); | 
|  | 1188 | assert(path.Access != AS_public); | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1189 |  | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1190 | CXXBasePath::iterator i = path.end(), e = path.begin(); | 
|  | 1191 | CXXBasePath::iterator constrainingBase = i; | 
|  | 1192 | while (i != e) { | 
|  | 1193 | --i; | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1194 |  | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1195 | assert(accessSoFar != AS_none && accessSoFar != AS_private); | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1196 |  | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1197 | // Is the entity accessible when named in the deriving class, as | 
|  | 1198 | // modified by the base specifier? | 
|  | 1199 | const CXXRecordDecl *derivingClass = i->Class->getCanonicalDecl(); | 
|  | 1200 | const CXXBaseSpecifier *base = i->Base; | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1201 |  | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1202 | // If the access to this base is worse than the access we have to | 
|  | 1203 | // the declaration, remember it. | 
|  | 1204 | AccessSpecifier baseAccess = base->getAccessSpecifier(); | 
|  | 1205 | if (baseAccess > accessSoFar) { | 
|  | 1206 | constrainingBase = i; | 
|  | 1207 | accessSoFar = baseAccess; | 
|  | 1208 | } | 
|  | 1209 |  | 
|  | 1210 | switch (HasAccess(S, EC, derivingClass, accessSoFar, entity)) { | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1211 | case AR_inaccessible: break; | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1212 | case AR_accessible: | 
|  | 1213 | accessSoFar = AS_public; | 
|  | 1214 | entity.suppressInstanceContext(); | 
| Craig Topper | c3ec149 | 2014-05-26 06:22:03 +0000 | [diff] [blame] | 1215 | constrainingBase = nullptr; | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1216 | break; | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1217 | case AR_dependent: | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1218 | llvm_unreachable("cannot diagnose dependent access"); | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1219 | } | 
|  | 1220 |  | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1221 | // If this was private inheritance, but we don't have access to | 
|  | 1222 | // the deriving class, we're done. | 
|  | 1223 | if (accessSoFar == AS_private) { | 
|  | 1224 | assert(baseAccess == AS_private); | 
|  | 1225 | assert(constrainingBase == i); | 
|  | 1226 | break; | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1227 | } | 
|  | 1228 | } | 
|  | 1229 |  | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1230 | // If we don't have a constraining base, the access failure must be | 
|  | 1231 | // due to the original declaration. | 
|  | 1232 | if (constrainingBase == path.end()) | 
|  | 1233 | return diagnoseBadDirectAccess(S, EC, entity); | 
|  | 1234 |  | 
|  | 1235 | // We're constrained by inheritance, but we want to say | 
|  | 1236 | // "declared private here" if we're diagnosing a hierarchy | 
|  | 1237 | // conversion and this is the final step. | 
|  | 1238 | unsigned diagnostic; | 
|  | 1239 | if (entity.isMemberAccess() || | 
|  | 1240 | constrainingBase + 1 != path.end()) { | 
|  | 1241 | diagnostic = diag::note_access_constrained_by_path; | 
|  | 1242 | } else { | 
|  | 1243 | diagnostic = diag::note_access_natural; | 
|  | 1244 | } | 
|  | 1245 |  | 
|  | 1246 | const CXXBaseSpecifier *base = constrainingBase->Base; | 
|  | 1247 |  | 
|  | 1248 | S.Diag(base->getSourceRange().getBegin(), diagnostic) | 
|  | 1249 | << base->getSourceRange() | 
|  | 1250 | << (base->getAccessSpecifier() == AS_protected) | 
|  | 1251 | << (base->getAccessSpecifierAsWritten() == AS_none); | 
|  | 1252 |  | 
|  | 1253 | if (entity.isMemberAccess()) | 
| Alp Toker | 2afa878 | 2014-05-28 12:20:14 +0000 | [diff] [blame] | 1254 | S.Diag(entity.getTargetDecl()->getLocation(), | 
|  | 1255 | diag::note_member_declared_at); | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1256 | } | 
|  | 1257 |  | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1258 | static void DiagnoseBadAccess(Sema &S, SourceLocation Loc, | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1259 | const EffectiveContext &EC, | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1260 | AccessTarget &Entity) { | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1261 | const CXXRecordDecl *NamingClass = Entity.getNamingClass(); | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1262 | const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); | 
| Craig Topper | c3ec149 | 2014-05-26 06:22:03 +0000 | [diff] [blame] | 1263 | NamedDecl *D = (Entity.isMemberAccess() ? Entity.getTargetDecl() : nullptr); | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1264 |  | 
|  | 1265 | S.Diag(Loc, Entity.getDiag()) | 
|  | 1266 | << (Entity.getAccess() == AS_protected) | 
|  | 1267 | << (D ? D->getDeclName() : DeclarationName()) | 
|  | 1268 | << S.Context.getTypeDeclType(NamingClass) | 
|  | 1269 | << S.Context.getTypeDeclType(DeclaringClass); | 
|  | 1270 | DiagnoseAccessPath(S, EC, Entity); | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1271 | } | 
|  | 1272 |  | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 1273 | /// MSVC has a bug where if during an using declaration name lookup, | 
|  | 1274 | /// the declaration found is unaccessible (private) and that declaration | 
| Francois Pichet | efb1af9 | 2011-05-23 03:43:44 +0000 | [diff] [blame] | 1275 | /// was bring into scope via another using declaration whose target | 
|  | 1276 | /// declaration is accessible (public) then no error is generated. | 
|  | 1277 | /// Example: | 
|  | 1278 | ///   class A { | 
|  | 1279 | ///   public: | 
|  | 1280 | ///     int f(); | 
|  | 1281 | ///   }; | 
|  | 1282 | ///   class B : public A { | 
|  | 1283 | ///   private: | 
|  | 1284 | ///     using A::f; | 
|  | 1285 | ///   }; | 
|  | 1286 | ///   class C : public B { | 
|  | 1287 | ///   private: | 
|  | 1288 | ///     using B::f; | 
|  | 1289 | ///   }; | 
|  | 1290 | /// | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 1291 | /// Here, B::f is private so this should fail in Standard C++, but | 
| Francois Pichet | efb1af9 | 2011-05-23 03:43:44 +0000 | [diff] [blame] | 1292 | /// because B::f refers to A::f which is public MSVC accepts it. | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 1293 | static bool IsMicrosoftUsingDeclarationAccessBug(Sema& S, | 
| Francois Pichet | efb1af9 | 2011-05-23 03:43:44 +0000 | [diff] [blame] | 1294 | SourceLocation AccessLoc, | 
|  | 1295 | AccessTarget &Entity) { | 
|  | 1296 | if (UsingShadowDecl *Shadow = | 
|  | 1297 | dyn_cast<UsingShadowDecl>(Entity.getTargetDecl())) { | 
|  | 1298 | const NamedDecl *OrigDecl = Entity.getTargetDecl()->getUnderlyingDecl(); | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 1299 | if (Entity.getTargetDecl()->getAccess() == AS_private && | 
| Francois Pichet | efb1af9 | 2011-05-23 03:43:44 +0000 | [diff] [blame] | 1300 | (OrigDecl->getAccess() == AS_public || | 
|  | 1301 | OrigDecl->getAccess() == AS_protected)) { | 
| Richard Smith | e434590 | 2011-12-29 21:57:33 +0000 | [diff] [blame] | 1302 | S.Diag(AccessLoc, diag::ext_ms_using_declaration_inaccessible) | 
| Francois Pichet | efb1af9 | 2011-05-23 03:43:44 +0000 | [diff] [blame] | 1303 | << Shadow->getUsingDecl()->getQualifiedNameAsString() | 
|  | 1304 | << OrigDecl->getQualifiedNameAsString(); | 
|  | 1305 | return true; | 
|  | 1306 | } | 
|  | 1307 | } | 
|  | 1308 | return false; | 
|  | 1309 | } | 
|  | 1310 |  | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1311 | /// Determines whether the accessed entity is accessible.  Public members | 
|  | 1312 | /// have been weeded out by this point. | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1313 | static AccessResult IsAccessible(Sema &S, | 
|  | 1314 | const EffectiveContext &EC, | 
|  | 1315 | AccessTarget &Entity) { | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1316 | // Determine the actual naming class. | 
| John McCall | d010ac9 | 2013-02-27 00:08:19 +0000 | [diff] [blame] | 1317 | const CXXRecordDecl *NamingClass = Entity.getEffectiveNamingClass(); | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1318 |  | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1319 | AccessSpecifier UnprivilegedAccess = Entity.getAccess(); | 
|  | 1320 | assert(UnprivilegedAccess != AS_public && "public access not weeded out"); | 
|  | 1321 |  | 
|  | 1322 | // Before we try to recalculate access paths, try to white-list | 
|  | 1323 | // accesses which just trade in on the final step, i.e. accesses | 
|  | 1324 | // which don't require [M4] or [B4]. These are by far the most | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1325 | // common forms of privileged access. | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1326 | if (UnprivilegedAccess != AS_none) { | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1327 | switch (HasAccess(S, EC, NamingClass, UnprivilegedAccess, Entity)) { | 
|  | 1328 | case AR_dependent: | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1329 | // This is actually an interesting policy decision.  We don't | 
|  | 1330 | // *have* to delay immediately here: we can do the full access | 
|  | 1331 | // calculation in the hope that friendship on some intermediate | 
|  | 1332 | // class will make the declaration accessible non-dependently. | 
|  | 1333 | // But that's not cheap, and odds are very good (note: assertion | 
|  | 1334 | // made without data) that the friend declaration will determine | 
|  | 1335 | // access. | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1336 | return AR_dependent; | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1337 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1338 | case AR_accessible: return AR_accessible; | 
|  | 1339 | case AR_inaccessible: break; | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1340 | } | 
|  | 1341 | } | 
|  | 1342 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1343 | AccessTarget::SavedInstanceContext _ = Entity.saveInstanceContext(); | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1344 |  | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1345 | // We lower member accesses to base accesses by pretending that the | 
|  | 1346 | // member is a base class of its declaring class. | 
|  | 1347 | AccessSpecifier FinalAccess; | 
|  | 1348 |  | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1349 | if (Entity.isMemberAccess()) { | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1350 | // Determine if the declaration is accessible from EC when named | 
|  | 1351 | // in its declaring class. | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1352 | NamedDecl *Target = Entity.getTargetDecl(); | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1353 | const CXXRecordDecl *DeclaringClass = Entity.getDeclaringClass(); | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1354 |  | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1355 | FinalAccess = Target->getAccess(); | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1356 | switch (HasAccess(S, EC, DeclaringClass, FinalAccess, Entity)) { | 
|  | 1357 | case AR_accessible: | 
| John McCall | 5149fbf | 2013-02-22 03:52:55 +0000 | [diff] [blame] | 1358 | // Target is accessible at EC when named in its declaring class. | 
|  | 1359 | // We can now hill-climb and simply check whether the declaring | 
|  | 1360 | // class is accessible as a base of the naming class.  This is | 
|  | 1361 | // equivalent to checking the access of a notional public | 
|  | 1362 | // member with no instance context. | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1363 | FinalAccess = AS_public; | 
| John McCall | 5149fbf | 2013-02-22 03:52:55 +0000 | [diff] [blame] | 1364 | Entity.suppressInstanceContext(); | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1365 | break; | 
|  | 1366 | case AR_inaccessible: break; | 
|  | 1367 | case AR_dependent: return AR_dependent; // see above | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1368 | } | 
|  | 1369 |  | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1370 | if (DeclaringClass == NamingClass) | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1371 | return (FinalAccess == AS_public ? AR_accessible : AR_inaccessible); | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1372 | } else { | 
|  | 1373 | FinalAccess = AS_public; | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1374 | } | 
|  | 1375 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1376 | assert(Entity.getDeclaringClass() != NamingClass); | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1377 |  | 
|  | 1378 | // Append the declaration's access if applicable. | 
|  | 1379 | CXXBasePaths Paths; | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1380 | CXXBasePath *Path = FindBestPath(S, EC, Entity, FinalAccess, Paths); | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 1381 | if (!Path) | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1382 | return AR_dependent; | 
| John McCall | 553c079 | 2010-01-23 00:46:32 +0000 | [diff] [blame] | 1383 |  | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1384 | assert(Path->Access <= UnprivilegedAccess && | 
|  | 1385 | "access along best path worse than direct?"); | 
|  | 1386 | if (Path->Access == AS_public) | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1387 | return AR_accessible; | 
|  | 1388 | return AR_inaccessible; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 1389 | } | 
|  | 1390 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1391 | static void DelayDependentAccess(Sema &S, | 
|  | 1392 | const EffectiveContext &EC, | 
|  | 1393 | SourceLocation Loc, | 
|  | 1394 | const AccessTarget &Entity) { | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 1395 | assert(EC.isDependent() && "delaying non-dependent access"); | 
| John McCall | 816d75b | 2010-03-24 07:46:06 +0000 | [diff] [blame] | 1396 | DeclContext *DC = EC.getInnerContext(); | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 1397 | assert(DC->isDependentContext() && "delaying non-dependent access"); | 
|  | 1398 | DependentDiagnostic::Create(S.Context, DC, DependentDiagnostic::Access, | 
|  | 1399 | Loc, | 
|  | 1400 | Entity.isMemberAccess(), | 
|  | 1401 | Entity.getAccess(), | 
|  | 1402 | Entity.getTargetDecl(), | 
|  | 1403 | Entity.getNamingClass(), | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1404 | Entity.getBaseObjectType(), | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 1405 | Entity.getDiag()); | 
| John McCall | 553c079 | 2010-01-23 00:46:32 +0000 | [diff] [blame] | 1406 | } | 
|  | 1407 |  | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1408 | /// Checks access to an entity from the given effective context. | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1409 | static AccessResult CheckEffectiveAccess(Sema &S, | 
|  | 1410 | const EffectiveContext &EC, | 
|  | 1411 | SourceLocation Loc, | 
|  | 1412 | AccessTarget &Entity) { | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1413 | assert(Entity.getAccess() != AS_public && "called for public access!"); | 
| John McCall | 553c079 | 2010-01-23 00:46:32 +0000 | [diff] [blame] | 1414 |  | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1415 | switch (IsAccessible(S, EC, Entity)) { | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1416 | case AR_dependent: | 
|  | 1417 | DelayDependentAccess(S, EC, Loc, Entity); | 
|  | 1418 | return AR_dependent; | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1419 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1420 | case AR_inaccessible: | 
| Reid Kleckner | 42063b0 | 2014-02-08 02:40:20 +0000 | [diff] [blame] | 1421 | if (S.getLangOpts().MSVCCompat && | 
|  | 1422 | IsMicrosoftUsingDeclarationAccessBug(S, Loc, Entity)) | 
|  | 1423 | return AR_accessible; | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1424 | if (!Entity.isQuiet()) | 
|  | 1425 | DiagnoseBadAccess(S, Loc, EC, Entity); | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1426 | return AR_inaccessible; | 
| John McCall | d79b4d8 | 2010-04-02 00:03:43 +0000 | [diff] [blame] | 1427 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1428 | case AR_accessible: | 
|  | 1429 | return AR_accessible; | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 1430 | } | 
|  | 1431 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1432 | // silence unnecessary warning | 
|  | 1433 | llvm_unreachable("invalid access result"); | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1434 | } | 
| John McCall | 553c079 | 2010-01-23 00:46:32 +0000 | [diff] [blame] | 1435 |  | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1436 | static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc, | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1437 | AccessTarget &Entity) { | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1438 | // If the access path is public, it's accessible everywhere. | 
|  | 1439 | if (Entity.getAccess() == AS_public) | 
|  | 1440 | return Sema::AR_accessible; | 
| John McCall | 553c079 | 2010-01-23 00:46:32 +0000 | [diff] [blame] | 1441 |  | 
| John McCall | c146582 | 2011-02-14 07:13:47 +0000 | [diff] [blame] | 1442 | // If we're currently parsing a declaration, we may need to delay | 
|  | 1443 | // access control checking, because our effective context might be | 
|  | 1444 | // different based on what the declaration comes out as. | 
|  | 1445 | // | 
|  | 1446 | // For example, we might be parsing a declaration with a scope | 
|  | 1447 | // specifier, like this: | 
|  | 1448 | //   A::private_type A::foo() { ... } | 
|  | 1449 | // | 
|  | 1450 | // Or we might be parsing something that will turn out to be a friend: | 
|  | 1451 | //   void foo(A::private_type); | 
|  | 1452 | //   void B::foo(A::private_type); | 
|  | 1453 | if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { | 
|  | 1454 | S.DelayedDiagnostics.add(DelayedDiagnostic::makeAccess(Loc, Entity)); | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1455 | return Sema::AR_delayed; | 
| John McCall | 553c079 | 2010-01-23 00:46:32 +0000 | [diff] [blame] | 1456 | } | 
|  | 1457 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1458 | EffectiveContext EC(S.CurContext); | 
|  | 1459 | switch (CheckEffectiveAccess(S, EC, Loc, Entity)) { | 
|  | 1460 | case AR_accessible: return Sema::AR_accessible; | 
|  | 1461 | case AR_inaccessible: return Sema::AR_inaccessible; | 
|  | 1462 | case AR_dependent: return Sema::AR_dependent; | 
|  | 1463 | } | 
| Davide Italiano | 24e8966 | 2015-05-17 02:27:10 +0000 | [diff] [blame] | 1464 | llvm_unreachable("invalid access result"); | 
| John McCall | 553c079 | 2010-01-23 00:46:32 +0000 | [diff] [blame] | 1465 | } | 
|  | 1466 |  | 
| Richard Smith | ad5c1ca | 2013-04-29 10:13:55 +0000 | [diff] [blame] | 1467 | void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) { | 
| John McCall | 9743e8d | 2011-02-15 22:51:53 +0000 | [diff] [blame] | 1468 | // Access control for names used in the declarations of functions | 
|  | 1469 | // and function templates should normally be evaluated in the context | 
|  | 1470 | // of the declaration, just in case it's a friend of something. | 
|  | 1471 | // However, this does not apply to local extern declarations. | 
|  | 1472 |  | 
| Richard Smith | ad5c1ca | 2013-04-29 10:13:55 +0000 | [diff] [blame] | 1473 | DeclContext *DC = D->getDeclContext(); | 
| Richard Smith | 608da01 | 2013-12-11 03:35:27 +0000 | [diff] [blame] | 1474 | if (D->isLocalExternDecl()) { | 
|  | 1475 | DC = D->getLexicalDeclContext(); | 
|  | 1476 | } else if (FunctionDecl *FN = dyn_cast<FunctionDecl>(D)) { | 
|  | 1477 | DC = FN; | 
| Richard Smith | ad5c1ca | 2013-04-29 10:13:55 +0000 | [diff] [blame] | 1478 | } else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) { | 
|  | 1479 | DC = cast<DeclContext>(TD->getTemplatedDecl()); | 
| John McCall | 9743e8d | 2011-02-15 22:51:53 +0000 | [diff] [blame] | 1480 | } | 
|  | 1481 |  | 
| Chandler Carruth | aad3007 | 2010-04-18 08:23:21 +0000 | [diff] [blame] | 1482 | EffectiveContext EC(DC); | 
| John McCall | 8612151 | 2010-01-27 03:50:35 +0000 | [diff] [blame] | 1483 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1484 | AccessTarget Target(DD.getAccessData()); | 
|  | 1485 |  | 
|  | 1486 | if (CheckEffectiveAccess(*this, EC, DD.Loc, Target) == ::AR_inaccessible) | 
| John McCall | 8612151 | 2010-01-27 03:50:35 +0000 | [diff] [blame] | 1487 | DD.Triggered = true; | 
|  | 1488 | } | 
|  | 1489 |  | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 1490 | void Sema::HandleDependentAccessCheck(const DependentDiagnostic &DD, | 
|  | 1491 | const MultiLevelTemplateArgumentList &TemplateArgs) { | 
|  | 1492 | SourceLocation Loc = DD.getAccessLoc(); | 
|  | 1493 | AccessSpecifier Access = DD.getAccess(); | 
|  | 1494 |  | 
|  | 1495 | Decl *NamingD = FindInstantiatedDecl(Loc, DD.getAccessNamingClass(), | 
|  | 1496 | TemplateArgs); | 
|  | 1497 | if (!NamingD) return; | 
|  | 1498 | Decl *TargetD = FindInstantiatedDecl(Loc, DD.getAccessTarget(), | 
|  | 1499 | TemplateArgs); | 
|  | 1500 | if (!TargetD) return; | 
|  | 1501 |  | 
|  | 1502 | if (DD.isAccessToMember()) { | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1503 | CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(NamingD); | 
|  | 1504 | NamedDecl *TargetDecl = cast<NamedDecl>(TargetD); | 
|  | 1505 | QualType BaseObjectType = DD.getAccessBaseObjectType(); | 
|  | 1506 | if (!BaseObjectType.isNull()) { | 
|  | 1507 | BaseObjectType = SubstType(BaseObjectType, TemplateArgs, Loc, | 
|  | 1508 | DeclarationName()); | 
|  | 1509 | if (BaseObjectType.isNull()) return; | 
|  | 1510 | } | 
|  | 1511 |  | 
|  | 1512 | AccessTarget Entity(Context, | 
|  | 1513 | AccessTarget::Member, | 
|  | 1514 | NamingClass, | 
|  | 1515 | DeclAccessPair::make(TargetDecl, Access), | 
|  | 1516 | BaseObjectType); | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 1517 | Entity.setDiag(DD.getDiagnostic()); | 
|  | 1518 | CheckAccess(*this, Loc, Entity); | 
|  | 1519 | } else { | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1520 | AccessTarget Entity(Context, | 
|  | 1521 | AccessTarget::Base, | 
|  | 1522 | cast<CXXRecordDecl>(TargetD), | 
|  | 1523 | cast<CXXRecordDecl>(NamingD), | 
|  | 1524 | Access); | 
| John McCall | c62bb64 | 2010-03-24 05:22:00 +0000 | [diff] [blame] | 1525 | Entity.setDiag(DD.getDiagnostic()); | 
|  | 1526 | CheckAccess(*this, Loc, Entity); | 
|  | 1527 | } | 
|  | 1528 | } | 
|  | 1529 |  | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1530 | Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, | 
| John McCall | a0296f7 | 2010-03-19 07:35:19 +0000 | [diff] [blame] | 1531 | DeclAccessPair Found) { | 
| David Blaikie | bbafb8a | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 1532 | if (!getLangOpts().AccessControl || | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1533 | !E->getNamingClass() || | 
| John McCall | a0296f7 | 2010-03-19 07:35:19 +0000 | [diff] [blame] | 1534 | Found.getAccess() == AS_public) | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1535 | return AR_accessible; | 
| John McCall | 58cc69d | 2010-01-27 01:50:18 +0000 | [diff] [blame] | 1536 |  | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 1537 | AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(), | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1538 | Found, QualType()); | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1539 | Entity.setDiag(diag::err_access) << E->getSourceRange(); | 
|  | 1540 |  | 
|  | 1541 | return CheckAccess(*this, E->getNameLoc(), Entity); | 
| John McCall | 58cc69d | 2010-01-27 01:50:18 +0000 | [diff] [blame] | 1542 | } | 
|  | 1543 |  | 
|  | 1544 | /// Perform access-control checking on a previously-unresolved member | 
|  | 1545 | /// access which has now been resolved to a member. | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1546 | Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, | 
| John McCall | a0296f7 | 2010-03-19 07:35:19 +0000 | [diff] [blame] | 1547 | DeclAccessPair Found) { | 
| David Blaikie | bbafb8a | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 1548 | if (!getLangOpts().AccessControl || | 
| John McCall | a0296f7 | 2010-03-19 07:35:19 +0000 | [diff] [blame] | 1549 | Found.getAccess() == AS_public) | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1550 | return AR_accessible; | 
| John McCall | 58cc69d | 2010-01-27 01:50:18 +0000 | [diff] [blame] | 1551 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1552 | QualType BaseType = E->getBaseType(); | 
|  | 1553 | if (E->isArrow()) | 
| Simon Pilgrim | dc4d908 | 2019-10-07 14:25:46 +0000 | [diff] [blame] | 1554 | BaseType = BaseType->castAs<PointerType>()->getPointeeType(); | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1555 |  | 
|  | 1556 | AccessTarget Entity(Context, AccessTarget::Member, E->getNamingClass(), | 
|  | 1557 | Found, BaseType); | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1558 | Entity.setDiag(diag::err_access) << E->getSourceRange(); | 
|  | 1559 |  | 
|  | 1560 | return CheckAccess(*this, E->getMemberLoc(), Entity); | 
| John McCall | 58cc69d | 2010-01-27 01:50:18 +0000 | [diff] [blame] | 1561 | } | 
|  | 1562 |  | 
| John McCall | d427421 | 2012-04-09 20:53:23 +0000 | [diff] [blame] | 1563 | /// Is the given special member function accessible for the purposes of | 
|  | 1564 | /// deciding whether to define a special member function as deleted? | 
|  | 1565 | bool Sema::isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl, | 
|  | 1566 | AccessSpecifier access, | 
|  | 1567 | QualType objectType) { | 
|  | 1568 | // Fast path. | 
|  | 1569 | if (access == AS_public || !getLangOpts().AccessControl) return true; | 
|  | 1570 |  | 
|  | 1571 | AccessTarget entity(Context, AccessTarget::Member, decl->getParent(), | 
|  | 1572 | DeclAccessPair::make(decl, access), objectType); | 
|  | 1573 |  | 
|  | 1574 | // Suppress diagnostics. | 
|  | 1575 | entity.setDiag(PDiag()); | 
|  | 1576 |  | 
|  | 1577 | switch (CheckAccess(*this, SourceLocation(), entity)) { | 
|  | 1578 | case AR_accessible: return true; | 
|  | 1579 | case AR_inaccessible: return false; | 
|  | 1580 | case AR_dependent: llvm_unreachable("dependent for =delete computation"); | 
|  | 1581 | case AR_delayed: llvm_unreachable("cannot delay =delete computation"); | 
|  | 1582 | } | 
|  | 1583 | llvm_unreachable("bad access result"); | 
|  | 1584 | } | 
|  | 1585 |  | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1586 | Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1587 | CXXDestructorDecl *Dtor, | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1588 | const PartialDiagnostic &PDiag, | 
|  | 1589 | QualType ObjectTy) { | 
| David Blaikie | bbafb8a | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 1590 | if (!getLangOpts().AccessControl) | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1591 | return AR_accessible; | 
| John McCall | 6781b05 | 2010-02-02 08:45:54 +0000 | [diff] [blame] | 1592 |  | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1593 | // There's never a path involved when checking implicit destructor access. | 
| John McCall | 6781b05 | 2010-02-02 08:45:54 +0000 | [diff] [blame] | 1594 | AccessSpecifier Access = Dtor->getAccess(); | 
|  | 1595 | if (Access == AS_public) | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1596 | return AR_accessible; | 
| John McCall | 6781b05 | 2010-02-02 08:45:54 +0000 | [diff] [blame] | 1597 |  | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1598 | CXXRecordDecl *NamingClass = Dtor->getParent(); | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1599 | if (ObjectTy.isNull()) ObjectTy = Context.getTypeDeclType(NamingClass); | 
|  | 1600 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1601 | AccessTarget Entity(Context, AccessTarget::Member, NamingClass, | 
|  | 1602 | DeclAccessPair::make(Dtor, Access), | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1603 | ObjectTy); | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1604 | Entity.setDiag(PDiag); // TODO: avoid copy | 
|  | 1605 |  | 
|  | 1606 | return CheckAccess(*this, Loc, Entity); | 
| John McCall | 6781b05 | 2010-02-02 08:45:54 +0000 | [diff] [blame] | 1607 | } | 
|  | 1608 |  | 
| John McCall | 760af17 | 2010-02-01 03:16:54 +0000 | [diff] [blame] | 1609 | /// Checks access to a constructor. | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1610 | Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, | 
| Jeffrey Yasskin | caa710d | 2010-06-07 15:58:05 +0000 | [diff] [blame] | 1611 | CXXConstructorDecl *Constructor, | 
| Richard Smith | 5179eb7 | 2016-06-28 19:03:57 +0000 | [diff] [blame] | 1612 | DeclAccessPair Found, | 
| Jeffrey Yasskin | caa710d | 2010-06-07 15:58:05 +0000 | [diff] [blame] | 1613 | const InitializedEntity &Entity, | 
| Jeffrey Yasskin | caa710d | 2010-06-07 15:58:05 +0000 | [diff] [blame] | 1614 | bool IsCopyBindingRefToTemp) { | 
| Richard Smith | 5179eb7 | 2016-06-28 19:03:57 +0000 | [diff] [blame] | 1615 | if (!getLangOpts().AccessControl || Found.getAccess() == AS_public) | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1616 | return AR_accessible; | 
| John McCall | 760af17 | 2010-02-01 03:16:54 +0000 | [diff] [blame] | 1617 |  | 
| Alexis Hunt | eef8ee0 | 2011-06-10 03:50:41 +0000 | [diff] [blame] | 1618 | PartialDiagnostic PD(PDiag()); | 
| Anders Carlsson | a01874b | 2010-04-21 18:47:17 +0000 | [diff] [blame] | 1619 | switch (Entity.getKind()) { | 
|  | 1620 | default: | 
| Alexis Hunt | eef8ee0 | 2011-06-10 03:50:41 +0000 | [diff] [blame] | 1621 | PD = PDiag(IsCopyBindingRefToTemp | 
|  | 1622 | ? diag::ext_rvalue_to_reference_access_ctor | 
|  | 1623 | : diag::err_access_ctor); | 
|  | 1624 |  | 
| Anders Carlsson | a01874b | 2010-04-21 18:47:17 +0000 | [diff] [blame] | 1625 | break; | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1626 |  | 
| Anders Carlsson | 05bf009 | 2010-04-22 05:40:53 +0000 | [diff] [blame] | 1627 | case InitializedEntity::EK_Base: | 
| Alexis Hunt | eef8ee0 | 2011-06-10 03:50:41 +0000 | [diff] [blame] | 1628 | PD = PDiag(diag::err_access_base_ctor); | 
|  | 1629 | PD << Entity.isInheritedVirtualBase() | 
|  | 1630 | << Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor); | 
| Anders Carlsson | a01874b | 2010-04-21 18:47:17 +0000 | [diff] [blame] | 1631 | break; | 
| Anders Carlsson | 05bf009 | 2010-04-22 05:40:53 +0000 | [diff] [blame] | 1632 |  | 
| Anders Carlsson | 4bb6e92 | 2010-04-21 20:28:29 +0000 | [diff] [blame] | 1633 | case InitializedEntity::EK_Member: { | 
|  | 1634 | const FieldDecl *Field = cast<FieldDecl>(Entity.getDecl()); | 
| Alexis Hunt | eef8ee0 | 2011-06-10 03:50:41 +0000 | [diff] [blame] | 1635 | PD = PDiag(diag::err_access_field_ctor); | 
|  | 1636 | PD << Field->getType() << getSpecialMember(Constructor); | 
| Anders Carlsson | 4bb6e92 | 2010-04-21 20:28:29 +0000 | [diff] [blame] | 1637 | break; | 
|  | 1638 | } | 
| Anders Carlsson | a01874b | 2010-04-21 18:47:17 +0000 | [diff] [blame] | 1639 |  | 
| Douglas Gregor | 19666fb | 2012-02-15 16:57:26 +0000 | [diff] [blame] | 1640 | case InitializedEntity::EK_LambdaCapture: { | 
| Faisal Vali | 5fb7c3c | 2013-12-05 01:40:41 +0000 | [diff] [blame] | 1641 | StringRef VarName = Entity.getCapturedVarName(); | 
| Douglas Gregor | 19666fb | 2012-02-15 16:57:26 +0000 | [diff] [blame] | 1642 | PD = PDiag(diag::err_access_lambda_capture); | 
| Faisal Vali | 5fb7c3c | 2013-12-05 01:40:41 +0000 | [diff] [blame] | 1643 | PD << VarName << Entity.getType() << getSpecialMember(Constructor); | 
| Douglas Gregor | 19666fb | 2012-02-15 16:57:26 +0000 | [diff] [blame] | 1644 | break; | 
|  | 1645 | } | 
|  | 1646 |  | 
| Anders Carlsson | 43c64af | 2010-04-21 19:52:01 +0000 | [diff] [blame] | 1647 | } | 
|  | 1648 |  | 
| Richard Smith | 5179eb7 | 2016-06-28 19:03:57 +0000 | [diff] [blame] | 1649 | return CheckConstructorAccess(UseLoc, Constructor, Found, Entity, PD); | 
| Alexis Hunt | eef8ee0 | 2011-06-10 03:50:41 +0000 | [diff] [blame] | 1650 | } | 
|  | 1651 |  | 
|  | 1652 | /// Checks access to a constructor. | 
|  | 1653 | Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, | 
|  | 1654 | CXXConstructorDecl *Constructor, | 
| Richard Smith | 5179eb7 | 2016-06-28 19:03:57 +0000 | [diff] [blame] | 1655 | DeclAccessPair Found, | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1656 | const InitializedEntity &Entity, | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1657 | const PartialDiagnostic &PD) { | 
| David Blaikie | bbafb8a | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 1658 | if (!getLangOpts().AccessControl || | 
| Richard Smith | 5179eb7 | 2016-06-28 19:03:57 +0000 | [diff] [blame] | 1659 | Found.getAccess() == AS_public) | 
| Alexis Hunt | eef8ee0 | 2011-06-10 03:50:41 +0000 | [diff] [blame] | 1660 | return AR_accessible; | 
|  | 1661 |  | 
|  | 1662 | CXXRecordDecl *NamingClass = Constructor->getParent(); | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1663 |  | 
|  | 1664 | // Initializing a base sub-object is an instance method call on an | 
|  | 1665 | // object of the derived class.  Otherwise, we have an instance method | 
|  | 1666 | // call on an object of the constructed type. | 
| Richard Smith | bbbe618 | 2016-03-08 23:17:35 +0000 | [diff] [blame] | 1667 | // | 
|  | 1668 | // FIXME: If we have a parent, we're initializing the base class subobject | 
|  | 1669 | // in aggregate initialization. It's not clear whether the object class | 
|  | 1670 | // should be the base class or the derived class in that case. | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1671 | CXXRecordDecl *ObjectClass; | 
| Richard Smith | 5179eb7 | 2016-06-28 19:03:57 +0000 | [diff] [blame] | 1672 | if ((Entity.getKind() == InitializedEntity::EK_Base || | 
|  | 1673 | Entity.getKind() == InitializedEntity::EK_Delegating) && | 
|  | 1674 | !Entity.getParent()) { | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1675 | ObjectClass = cast<CXXConstructorDecl>(CurContext)->getParent(); | 
| Richard Smith | 5179eb7 | 2016-06-28 19:03:57 +0000 | [diff] [blame] | 1676 | } else if (auto *Shadow = | 
|  | 1677 | dyn_cast<ConstructorUsingShadowDecl>(Found.getDecl())) { | 
|  | 1678 | // If we're using an inheriting constructor to construct an object, | 
|  | 1679 | // the object class is the derived class, not the base class. | 
|  | 1680 | ObjectClass = Shadow->getParent(); | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1681 | } else { | 
|  | 1682 | ObjectClass = NamingClass; | 
|  | 1683 | } | 
|  | 1684 |  | 
| Richard Smith | 5179eb7 | 2016-06-28 19:03:57 +0000 | [diff] [blame] | 1685 | AccessTarget AccessEntity( | 
|  | 1686 | Context, AccessTarget::Member, NamingClass, | 
|  | 1687 | DeclAccessPair::make(Constructor, Found.getAccess()), | 
|  | 1688 | Context.getTypeDeclType(ObjectClass)); | 
| Alexis Hunt | eef8ee0 | 2011-06-10 03:50:41 +0000 | [diff] [blame] | 1689 | AccessEntity.setDiag(PD); | 
|  | 1690 |  | 
| Anders Carlsson | a01874b | 2010-04-21 18:47:17 +0000 | [diff] [blame] | 1691 | return CheckAccess(*this, UseLoc, AccessEntity); | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 1692 | } | 
| John McCall | 760af17 | 2010-02-01 03:16:54 +0000 | [diff] [blame] | 1693 |  | 
| John McCall | fb6f526 | 2010-03-18 08:19:33 +0000 | [diff] [blame] | 1694 | /// Checks access to an overloaded operator new or delete. | 
|  | 1695 | Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, | 
|  | 1696 | SourceRange PlacementRange, | 
|  | 1697 | CXXRecordDecl *NamingClass, | 
| Alexis Hunt | f9172946 | 2011-05-12 22:46:25 +0000 | [diff] [blame] | 1698 | DeclAccessPair Found, | 
|  | 1699 | bool Diagnose) { | 
| David Blaikie | bbafb8a | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 1700 | if (!getLangOpts().AccessControl || | 
| John McCall | fb6f526 | 2010-03-18 08:19:33 +0000 | [diff] [blame] | 1701 | !NamingClass || | 
| John McCall | a0296f7 | 2010-03-19 07:35:19 +0000 | [diff] [blame] | 1702 | Found.getAccess() == AS_public) | 
| John McCall | fb6f526 | 2010-03-18 08:19:33 +0000 | [diff] [blame] | 1703 | return AR_accessible; | 
|  | 1704 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1705 | AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, | 
|  | 1706 | QualType()); | 
| Alexis Hunt | f9172946 | 2011-05-12 22:46:25 +0000 | [diff] [blame] | 1707 | if (Diagnose) | 
|  | 1708 | Entity.setDiag(diag::err_access) | 
|  | 1709 | << PlacementRange; | 
| John McCall | fb6f526 | 2010-03-18 08:19:33 +0000 | [diff] [blame] | 1710 |  | 
|  | 1711 | return CheckAccess(*this, OpLoc, Entity); | 
|  | 1712 | } | 
|  | 1713 |  | 
| Adrian Prantl | 9fc8faf | 2018-05-09 01:00:01 +0000 | [diff] [blame] | 1714 | /// Checks access to a member. | 
| Alexey Bataev | 5ec3eb1 | 2013-07-19 03:13:43 +0000 | [diff] [blame] | 1715 | Sema::AccessResult Sema::CheckMemberAccess(SourceLocation UseLoc, | 
|  | 1716 | CXXRecordDecl *NamingClass, | 
| Eli Friedman | 3be1a1c | 2013-10-01 02:44:48 +0000 | [diff] [blame] | 1717 | DeclAccessPair Found) { | 
| Alexey Bataev | 5ec3eb1 | 2013-07-19 03:13:43 +0000 | [diff] [blame] | 1718 | if (!getLangOpts().AccessControl || | 
|  | 1719 | !NamingClass || | 
| Eli Friedman | 3be1a1c | 2013-10-01 02:44:48 +0000 | [diff] [blame] | 1720 | Found.getAccess() == AS_public) | 
| Alexey Bataev | 5ec3eb1 | 2013-07-19 03:13:43 +0000 | [diff] [blame] | 1721 | return AR_accessible; | 
|  | 1722 |  | 
|  | 1723 | AccessTarget Entity(Context, AccessTarget::Member, NamingClass, | 
| Eli Friedman | 3be1a1c | 2013-10-01 02:44:48 +0000 | [diff] [blame] | 1724 | Found, QualType()); | 
| Alexey Bataev | 5ec3eb1 | 2013-07-19 03:13:43 +0000 | [diff] [blame] | 1725 |  | 
|  | 1726 | return CheckAccess(*this, UseLoc, Entity); | 
|  | 1727 | } | 
|  | 1728 |  | 
| Richard Smith | 5c9b3b7 | 2018-09-25 22:12:44 +0000 | [diff] [blame] | 1729 | /// Checks implicit access to a member in a structured binding. | 
|  | 1730 | Sema::AccessResult | 
|  | 1731 | Sema::CheckStructuredBindingMemberAccess(SourceLocation UseLoc, | 
|  | 1732 | CXXRecordDecl *DecomposedClass, | 
|  | 1733 | DeclAccessPair Field) { | 
|  | 1734 | if (!getLangOpts().AccessControl || | 
|  | 1735 | Field.getAccess() == AS_public) | 
|  | 1736 | return AR_accessible; | 
|  | 1737 |  | 
|  | 1738 | AccessTarget Entity(Context, AccessTarget::Member, DecomposedClass, Field, | 
|  | 1739 | Context.getRecordType(DecomposedClass)); | 
|  | 1740 | Entity.setDiag(diag::err_decomp_decl_inaccessible_field); | 
|  | 1741 |  | 
|  | 1742 | return CheckAccess(*this, UseLoc, Entity); | 
|  | 1743 | } | 
|  | 1744 |  | 
| John McCall | 760af17 | 2010-02-01 03:16:54 +0000 | [diff] [blame] | 1745 | /// Checks access to an overloaded member operator, including | 
|  | 1746 | /// conversion operators. | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1747 | Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, | 
|  | 1748 | Expr *ObjectExpr, | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1749 | Expr *ArgExpr, | 
| John McCall | a0296f7 | 2010-03-19 07:35:19 +0000 | [diff] [blame] | 1750 | DeclAccessPair Found) { | 
| David Blaikie | bbafb8a | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 1751 | if (!getLangOpts().AccessControl || | 
| John McCall | a0296f7 | 2010-03-19 07:35:19 +0000 | [diff] [blame] | 1752 | Found.getAccess() == AS_public) | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1753 | return AR_accessible; | 
| John McCall | b3a4400 | 2010-01-28 01:42:12 +0000 | [diff] [blame] | 1754 |  | 
| John McCall | 3090903 | 2011-09-21 08:36:56 +0000 | [diff] [blame] | 1755 | const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>(); | 
| John McCall | b3a4400 | 2010-01-28 01:42:12 +0000 | [diff] [blame] | 1756 | CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl()); | 
|  | 1757 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1758 | AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, | 
|  | 1759 | ObjectExpr->getType()); | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1760 | Entity.setDiag(diag::err_access) | 
|  | 1761 | << ObjectExpr->getSourceRange() | 
|  | 1762 | << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange()); | 
|  | 1763 |  | 
|  | 1764 | return CheckAccess(*this, OpLoc, Entity); | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1765 | } | 
| John McCall | b3a4400 | 2010-01-28 01:42:12 +0000 | [diff] [blame] | 1766 |  | 
| John McCall | a0a9689 | 2012-08-10 03:15:35 +0000 | [diff] [blame] | 1767 | /// Checks access to the target of a friend declaration. | 
|  | 1768 | Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) { | 
| Alp Toker | a2794f9 | 2014-01-22 07:29:52 +0000 | [diff] [blame] | 1769 | assert(isa<CXXMethodDecl>(target->getAsFunction())); | 
| John McCall | a0a9689 | 2012-08-10 03:15:35 +0000 | [diff] [blame] | 1770 |  | 
|  | 1771 | // Friendship lookup is a redeclaration lookup, so there's never an | 
|  | 1772 | // inheritance path modifying access. | 
|  | 1773 | AccessSpecifier access = target->getAccess(); | 
|  | 1774 |  | 
|  | 1775 | if (!getLangOpts().AccessControl || access == AS_public) | 
|  | 1776 | return AR_accessible; | 
|  | 1777 |  | 
| Alp Toker | 2bd4a28 | 2014-01-22 07:53:08 +0000 | [diff] [blame] | 1778 | CXXMethodDecl *method = cast<CXXMethodDecl>(target->getAsFunction()); | 
| John McCall | a0a9689 | 2012-08-10 03:15:35 +0000 | [diff] [blame] | 1779 |  | 
|  | 1780 | AccessTarget entity(Context, AccessTarget::Member, | 
|  | 1781 | cast<CXXRecordDecl>(target->getDeclContext()), | 
|  | 1782 | DeclAccessPair::make(target, access), | 
|  | 1783 | /*no instance context*/ QualType()); | 
|  | 1784 | entity.setDiag(diag::err_access_friend_function) | 
| Reid Kleckner | af9bf59 | 2014-12-17 23:40:46 +0000 | [diff] [blame] | 1785 | << (method->getQualifier() ? method->getQualifierLoc().getSourceRange() | 
|  | 1786 | : method->getNameInfo().getSourceRange()); | 
| John McCall | a0a9689 | 2012-08-10 03:15:35 +0000 | [diff] [blame] | 1787 |  | 
|  | 1788 | // We need to bypass delayed-diagnostics because we might be called | 
|  | 1789 | // while the ParsingDeclarator is active. | 
|  | 1790 | EffectiveContext EC(CurContext); | 
|  | 1791 | switch (CheckEffectiveAccess(*this, EC, target->getLocation(), entity)) { | 
| Etienne Bergeron | 4753302 | 2016-06-01 21:17:32 +0000 | [diff] [blame] | 1792 | case ::AR_accessible: return Sema::AR_accessible; | 
|  | 1793 | case ::AR_inaccessible: return Sema::AR_inaccessible; | 
|  | 1794 | case ::AR_dependent: return Sema::AR_dependent; | 
| John McCall | a0a9689 | 2012-08-10 03:15:35 +0000 | [diff] [blame] | 1795 | } | 
| Davide Italiano | 9b950d8 | 2015-07-29 20:55:04 +0000 | [diff] [blame] | 1796 | llvm_unreachable("invalid access result"); | 
| John McCall | a0a9689 | 2012-08-10 03:15:35 +0000 | [diff] [blame] | 1797 | } | 
|  | 1798 |  | 
| John McCall | 16df1e5 | 2010-03-30 21:47:33 +0000 | [diff] [blame] | 1799 | Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr, | 
|  | 1800 | DeclAccessPair Found) { | 
| David Blaikie | bbafb8a | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 1801 | if (!getLangOpts().AccessControl || | 
| John McCall | b493d53 | 2010-03-30 22:20:00 +0000 | [diff] [blame] | 1802 | Found.getAccess() == AS_none || | 
| John McCall | 16df1e5 | 2010-03-30 21:47:33 +0000 | [diff] [blame] | 1803 | Found.getAccess() == AS_public) | 
|  | 1804 | return AR_accessible; | 
|  | 1805 |  | 
| John McCall | 8d08b9b | 2010-08-27 09:08:28 +0000 | [diff] [blame] | 1806 | OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).Expression; | 
| John McCall | 8c12dc4 | 2010-04-22 18:44:12 +0000 | [diff] [blame] | 1807 | CXXRecordDecl *NamingClass = Ovl->getNamingClass(); | 
| John McCall | 16df1e5 | 2010-03-30 21:47:33 +0000 | [diff] [blame] | 1808 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1809 | AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, | 
| John McCall | 5dadb65 | 2012-04-07 03:04:20 +0000 | [diff] [blame] | 1810 | /*no instance context*/ QualType()); | 
| John McCall | 16df1e5 | 2010-03-30 21:47:33 +0000 | [diff] [blame] | 1811 | Entity.setDiag(diag::err_access) | 
|  | 1812 | << Ovl->getSourceRange(); | 
|  | 1813 |  | 
|  | 1814 | return CheckAccess(*this, Ovl->getNameLoc(), Entity); | 
|  | 1815 | } | 
|  | 1816 |  | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1817 | /// Checks access for a hierarchy conversion. | 
|  | 1818 | /// | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1819 | /// \param ForceCheck true if this check should be performed even if access | 
|  | 1820 | ///     control is disabled;  some things rely on this for semantics | 
|  | 1821 | /// \param ForceUnprivileged true if this check should proceed as if the | 
|  | 1822 | ///     context had no special privileges | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1823 | Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1824 | QualType Base, | 
|  | 1825 | QualType Derived, | 
|  | 1826 | const CXXBasePath &Path, | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1827 | unsigned DiagID, | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1828 | bool ForceCheck, | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1829 | bool ForceUnprivileged) { | 
| David Blaikie | bbafb8a | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 1830 | if (!ForceCheck && !getLangOpts().AccessControl) | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1831 | return AR_accessible; | 
| John McCall | b3a4400 | 2010-01-28 01:42:12 +0000 | [diff] [blame] | 1832 |  | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1833 | if (Path.Access == AS_public) | 
|  | 1834 | return AR_accessible; | 
| John McCall | b3a4400 | 2010-01-28 01:42:12 +0000 | [diff] [blame] | 1835 |  | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1836 | CXXRecordDecl *BaseD, *DerivedD; | 
| Simon Pilgrim | 1cd399c | 2019-10-03 11:22:48 +0000 | [diff] [blame] | 1837 | BaseD = cast<CXXRecordDecl>(Base->castAs<RecordType>()->getDecl()); | 
|  | 1838 | DerivedD = cast<CXXRecordDecl>(Derived->castAs<RecordType>()->getDecl()); | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1839 |  | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 1840 | AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD, | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1841 | Path.Access); | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1842 | if (DiagID) | 
|  | 1843 | Entity.setDiag(DiagID) << Derived << Base; | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1844 |  | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1845 | if (ForceUnprivileged) { | 
|  | 1846 | switch (CheckEffectiveAccess(*this, EffectiveContext(), | 
|  | 1847 | AccessLoc, Entity)) { | 
|  | 1848 | case ::AR_accessible: return Sema::AR_accessible; | 
|  | 1849 | case ::AR_inaccessible: return Sema::AR_inaccessible; | 
|  | 1850 | case ::AR_dependent: return Sema::AR_dependent; | 
|  | 1851 | } | 
|  | 1852 | llvm_unreachable("unexpected result from CheckEffectiveAccess"); | 
|  | 1853 | } | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1854 | return CheckAccess(*this, AccessLoc, Entity); | 
| John McCall | b3a4400 | 2010-01-28 01:42:12 +0000 | [diff] [blame] | 1855 | } | 
|  | 1856 |  | 
| John McCall | 553c079 | 2010-01-23 00:46:32 +0000 | [diff] [blame] | 1857 | /// Checks access to all the declarations in the given result set. | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1858 | void Sema::CheckLookupAccess(const LookupResult &R) { | 
| David Blaikie | bbafb8a | 2012-03-11 07:00:24 +0000 | [diff] [blame] | 1859 | assert(getLangOpts().AccessControl | 
| John McCall | 5b0829a | 2010-02-10 09:31:12 +0000 | [diff] [blame] | 1860 | && "performing access check without access control"); | 
|  | 1861 | assert(R.getNamingClass() && "performing access check without naming class"); | 
|  | 1862 |  | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1863 | for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { | 
|  | 1864 | if (I.getAccess() != AS_public) { | 
| John McCall | a8ae222 | 2010-04-06 21:38:20 +0000 | [diff] [blame] | 1865 | AccessTarget Entity(Context, AccessedEntity::Member, | 
|  | 1866 | R.getNamingClass(), I.getPair(), | 
| Erik Verbruggen | 631dfc6 | 2011-09-19 15:10:40 +0000 | [diff] [blame] | 1867 | R.getBaseObjectType()); | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1868 | Entity.setDiag(diag::err_access); | 
| John McCall | 1064d7e | 2010-03-16 05:22:47 +0000 | [diff] [blame] | 1869 | CheckAccess(*this, R.getNameLoc(), Entity); | 
|  | 1870 | } | 
|  | 1871 | } | 
| John McCall | 553c079 | 2010-01-23 00:46:32 +0000 | [diff] [blame] | 1872 | } | 
| Chandler Carruth | 2d69ec7 | 2010-06-28 08:39:25 +0000 | [diff] [blame] | 1873 |  | 
| Eric Liu | 18b404a | 2018-07-19 13:32:00 +0000 | [diff] [blame] | 1874 | /// Checks access to Target from the given class. The check will take access | 
| Erik Verbruggen | 2e657ff | 2011-10-06 07:27:49 +0000 | [diff] [blame] | 1875 | /// specifiers into account, but no member access expressions and such. | 
|  | 1876 | /// | 
| Eric Liu | 18b404a | 2018-07-19 13:32:00 +0000 | [diff] [blame] | 1877 | /// \param Target the declaration to check if it can be accessed | 
| Ilya Biryukov | f1822ec | 2018-12-03 13:29:17 +0000 | [diff] [blame] | 1878 | /// \param NamingClass the class in which the lookup was started. | 
|  | 1879 | /// \param BaseType type of the left side of member access expression. | 
|  | 1880 | ///        \p BaseType and \p NamingClass are used for C++ access control. | 
|  | 1881 | ///        Depending on the lookup case, they should be set to the following: | 
|  | 1882 | ///        - lhs.target (member access without a qualifier): | 
|  | 1883 | ///          \p BaseType and \p NamingClass are both the type of 'lhs'. | 
|  | 1884 | ///        - lhs.X::target (member access with a qualifier): | 
|  | 1885 | ///          BaseType is the type of 'lhs', NamingClass is 'X' | 
|  | 1886 | ///        - X::target (qualified lookup without member access): | 
|  | 1887 | ///          BaseType is null, NamingClass is 'X'. | 
|  | 1888 | ///        - target (unqualified lookup). | 
|  | 1889 | ///          BaseType is null, NamingClass is the parent class of 'target'. | 
| Eric Liu | 18b404a | 2018-07-19 13:32:00 +0000 | [diff] [blame] | 1890 | /// \return true if the Target is accessible from the Class, false otherwise. | 
| Ilya Biryukov | f1822ec | 2018-12-03 13:29:17 +0000 | [diff] [blame] | 1891 | bool Sema::IsSimplyAccessible(NamedDecl *Target, CXXRecordDecl *NamingClass, | 
|  | 1892 | QualType BaseType) { | 
|  | 1893 | // Perform the C++ accessibility checks first. | 
|  | 1894 | if (Target->isCXXClassMember() && NamingClass) { | 
|  | 1895 | if (!getLangOpts().CPlusPlus) | 
|  | 1896 | return false; | 
| Eric Liu | 18b404a | 2018-07-19 13:32:00 +0000 | [diff] [blame] | 1897 | // The unprivileged access is AS_none as we don't know how the member was | 
|  | 1898 | // accessed, which is described by the access in DeclAccessPair. | 
|  | 1899 | // `IsAccessible` will examine the actual access of Target (i.e. | 
|  | 1900 | // Decl->getAccess()) when calculating the access. | 
| Ilya Biryukov | f1822ec | 2018-12-03 13:29:17 +0000 | [diff] [blame] | 1901 | AccessTarget Entity(Context, AccessedEntity::Member, NamingClass, | 
|  | 1902 | DeclAccessPair::make(Target, AS_none), BaseType); | 
| Douglas Gregor | 03ba188 | 2011-11-03 16:51:37 +0000 | [diff] [blame] | 1903 | EffectiveContext EC(CurContext); | 
|  | 1904 | return ::IsAccessible(*this, EC, Entity) != ::AR_inaccessible; | 
|  | 1905 | } | 
| Eric Liu | 18b404a | 2018-07-19 13:32:00 +0000 | [diff] [blame] | 1906 |  | 
|  | 1907 | if (ObjCIvarDecl *Ivar = dyn_cast<ObjCIvarDecl>(Target)) { | 
| Douglas Gregor | 21ceb18 | 2011-11-03 19:00:24 +0000 | [diff] [blame] | 1908 | // @public and @package ivars are always accessible. | 
|  | 1909 | if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Public || | 
|  | 1910 | Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Package) | 
|  | 1911 | return true; | 
| Serge Pavlov | 64bc703 | 2013-05-07 16:56:03 +0000 | [diff] [blame] | 1912 |  | 
| Douglas Gregor | 21ceb18 | 2011-11-03 19:00:24 +0000 | [diff] [blame] | 1913 | // If we are inside a class or category implementation, determine the | 
|  | 1914 | // interface we're in. | 
| Craig Topper | c3ec149 | 2014-05-26 06:22:03 +0000 | [diff] [blame] | 1915 | ObjCInterfaceDecl *ClassOfMethodDecl = nullptr; | 
| Douglas Gregor | 21ceb18 | 2011-11-03 19:00:24 +0000 | [diff] [blame] | 1916 | if (ObjCMethodDecl *MD = getCurMethodDecl()) | 
|  | 1917 | ClassOfMethodDecl =  MD->getClassInterface(); | 
|  | 1918 | else if (FunctionDecl *FD = getCurFunctionDecl()) { | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 1919 | if (ObjCImplDecl *Impl | 
| Douglas Gregor | 21ceb18 | 2011-11-03 19:00:24 +0000 | [diff] [blame] | 1920 | = dyn_cast<ObjCImplDecl>(FD->getLexicalDeclContext())) { | 
|  | 1921 | if (ObjCImplementationDecl *IMPD | 
|  | 1922 | = dyn_cast<ObjCImplementationDecl>(Impl)) | 
|  | 1923 | ClassOfMethodDecl = IMPD->getClassInterface(); | 
|  | 1924 | else if (ObjCCategoryImplDecl* CatImplClass | 
|  | 1925 | = dyn_cast<ObjCCategoryImplDecl>(Impl)) | 
|  | 1926 | ClassOfMethodDecl = CatImplClass->getClassInterface(); | 
|  | 1927 | } | 
|  | 1928 | } | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 1929 |  | 
| Douglas Gregor | 21ceb18 | 2011-11-03 19:00:24 +0000 | [diff] [blame] | 1930 | // If we're not in an interface, this ivar is inaccessible. | 
|  | 1931 | if (!ClassOfMethodDecl) | 
|  | 1932 | return false; | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 1933 |  | 
| Douglas Gregor | 21ceb18 | 2011-11-03 19:00:24 +0000 | [diff] [blame] | 1934 | // If we're inside the same interface that owns the ivar, we're fine. | 
| Douglas Gregor | 0b144e1 | 2011-12-15 00:29:59 +0000 | [diff] [blame] | 1935 | if (declaresSameEntity(ClassOfMethodDecl, Ivar->getContainingInterface())) | 
| Douglas Gregor | 21ceb18 | 2011-11-03 19:00:24 +0000 | [diff] [blame] | 1936 | return true; | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 1937 |  | 
| Douglas Gregor | 21ceb18 | 2011-11-03 19:00:24 +0000 | [diff] [blame] | 1938 | // If the ivar is private, it's inaccessible. | 
|  | 1939 | if (Ivar->getCanonicalAccessControl() == ObjCIvarDecl::Private) | 
|  | 1940 | return false; | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 1941 |  | 
| Douglas Gregor | 21ceb18 | 2011-11-03 19:00:24 +0000 | [diff] [blame] | 1942 | return Ivar->getContainingInterface()->isSuperClassOf(ClassOfMethodDecl); | 
|  | 1943 | } | 
| Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 1944 |  | 
| Douglas Gregor | 03ba188 | 2011-11-03 16:51:37 +0000 | [diff] [blame] | 1945 | return true; | 
| Erik Verbruggen | 2e657ff | 2011-10-06 07:27:49 +0000 | [diff] [blame] | 1946 | } |