]> granicus.if.org Git - clang/commitdiff
First pass at collecting access-specifier information along inheritance paths.
authorJohn McCall <rjmccall@apple.com>
Wed, 20 Jan 2010 21:53:11 +0000 (21:53 +0000)
committerJohn McCall <rjmccall@apple.com>
Wed, 20 Jan 2010 21:53:11 +0000 (21:53 +0000)
Triggers lots of assertions about missing access information;  fix them.

Will actually consume this information soon.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94038 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/CXXInheritance.h
lib/AST/CXXInheritance.cpp
lib/AST/DeclBase.cpp
lib/Sema/Lookup.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaLookup.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp

index 7c826fe75d11e5194d96853f1036ad75b6336ec3..77356f2f4d8b088d5b0824dcf221e8437894b56f 100644 (file)
@@ -65,6 +65,9 @@ struct CXXBasePathElement {
 /// subobject is being used.
 class CXXBasePath : public llvm::SmallVector<CXXBasePathElement, 4> {
 public:
+  /// \brief The access along this inheritance path.
+  AccessSpecifier Access;
+
   /// \brief The set of declarations found inside this base class
   /// subobject.
   DeclContext::lookup_result Decls;
@@ -131,9 +134,13 @@ class CXXBasePaths {
   /// is also recorded.
   bool DetectVirtual;
   
-  /// ScratchPath - A BasePath that is used by Sema::IsDerivedFrom
+  /// ScratchPath - A BasePath that is used by Sema::lookupInBases
   /// to help build the set of paths.
   CXXBasePath ScratchPath;
+
+  /// ScratchAccess - A stack of accessibility annotations used by
+  /// Sema::lookupInBases.
+  llvm::SmallVector<AccessSpecifier, 4> ScratchAccess;
   
   /// DetectedVirtual - The base class that is virtual.
   const RecordType *DetectedVirtual;
index 92a58b76d87803a9074996898055df073183d1c5..d575ccd98265ed91fad2b2cd5bcb2b966b3aa347 100644 (file)
@@ -61,6 +61,7 @@ void CXXBasePaths::clear() {
   Paths.clear();
   ClassSubobjects.clear();
   ScratchPath.clear();
+  ScratchAccess.clear();
   DetectedVirtual = 0;
 }
 
@@ -145,7 +146,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
                                   void *UserData,
                                   CXXBasePaths &Paths) const {
   bool FoundPath = false;
-  
+
   ASTContext &Context = getASTContext();
   for (base_class_const_iterator BaseSpec = bases_begin(),
          BaseSpecEnd = bases_end(); BaseSpec != BaseSpecEnd; ++BaseSpec) {
@@ -189,6 +190,17 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
       else
         Element.SubobjectNumber = Subobjects.second;
       Paths.ScratchPath.push_back(Element);
+
+      // C++0x [class.access.base]p1 (paraphrased):
+      //   The access of a member of a base class is the less permissive
+      //   of its access within the base class and the access of the base
+      //   class within the derived class.
+      // We're just calculating the access along the path, so we ignore
+      // the access specifiers of whatever decls we've found.
+      AccessSpecifier PathAccess = Paths.ScratchPath.Access;
+      Paths.ScratchAccess.push_back(PathAccess);
+      Paths.ScratchPath.Access
+        = std::max(PathAccess, BaseSpec->getAccessSpecifier());
     }
         
     if (BaseMatches(BaseSpec, Paths.ScratchPath, UserData)) {
@@ -223,8 +235,12 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
     
     // Pop this base specifier off the current path (if we're
     // collecting paths).
-    if (Paths.isRecordingPaths())
+    if (Paths.isRecordingPaths()) {
       Paths.ScratchPath.pop_back();
+      Paths.ScratchPath.Access = Paths.ScratchAccess.back();
+      Paths.ScratchAccess.pop_back();
+    }
+
     // If we set a virtual earlier, and this isn't a path, forget it again.
     if (SetVirtual && !FoundPath) {
       Paths.DetectedVirtual = 0;
index 76ff83448a0300e3f5be5cdd2119aa4baf537111..95b749bfbbd84784f7f8079529a048cd13dbb281 100644 (file)
@@ -410,9 +410,16 @@ SourceLocation Decl::getBodyRBrace() const {
 
 #ifndef NDEBUG
 void Decl::CheckAccessDeclContext() const {
-  // If the decl is the toplevel translation unit or if we're not in a
-  // record decl context, we don't need to check anything.
+  // Suppress this check if any of the following hold:
+  // 1. this is the translation unit (and thus has no parent)
+  // 2. this is a template parameter (and thus doesn't belong to its context)
+  // 3. this is a ParmVarDecl (which can be in a record context during
+  //    the brief period between its creation and the creation of the
+  //    FunctionDecl)
+  // 4. the context is not a record
   if (isa<TranslationUnitDecl>(this) ||
+      isTemplateParameter() ||
+      isa<ParmVarDecl>(this) ||
       !isa<CXXRecordDecl>(getDeclContext()))
     return;
 
index 33d11065598865e6e352adc946f0aa3b5d27efac..274a3dabbf0946df9a515033844f681d96c3fdd5 100644 (file)
@@ -245,10 +245,16 @@ public:
     return IDNS;
   }
 
-  /// \brief Add a declaration to these results with no access bits.
+  /// \brief Add a declaration to these results with its natural access.
   /// Does not test the acceptance criteria.
   void addDecl(NamedDecl *D) {
-    Decls.addDecl(D);
+    addDecl(D, D->getAccess());
+  }
+
+  /// \brief Add a declaration to these results with the given access.
+  /// Does not test the acceptance criteria.
+  void addDecl(NamedDecl *D, AccessSpecifier AS) {
+    Decls.addDecl(D, AS);
     ResultKind = Found;
   }
 
index 1e46787d8f1343e20127e5833df55a867ee6321a..7e86120b169b7a33605a39dfb0d3c67b07c18a56 100644 (file)
@@ -1305,6 +1305,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
 
   // Keep a chain of previous declarations.
   New->setPreviousDeclaration(Old);
+
+  // Inherit access appropriately.
+  New->setAccess(Old->getAccess());
 }
 
 static void MarkLive(CFGBlock *e, llvm::BitVector &live) {
@@ -3361,6 +3364,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
   }
 
   if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) {
+    // Fake up an access specifier if it's supposed to be a class member.
+    if (isa<CXXRecordDecl>(NewFD->getDeclContext()))
+      NewFD->setAccess(AS_public);
+
     // An out-of-line member function declaration must also be a
     // definition (C++ [dcl.meaning]p1).
     // Note that this is not the case for explicit specializations of
index da7626780caafeefc64f29bcaacff1d5c8582e6d..ddce4a4c23db43e177fdd5101110f84a2888d36b 100644 (file)
@@ -445,8 +445,9 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) {
 
   DeclContext::lookup_const_iterator I, E;
   for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) {
-    if (R.isAcceptableDecl(*I)) {
-      R.addDecl(*I);
+    NamedDecl *D = *I;
+    if (R.isAcceptableDecl(D)) {
+      R.addDecl(D);
       Found = true;
     }
   }
@@ -1047,10 +1048,15 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
   // FIXME: support using declarations!
   QualType SubobjectType;
   int SubobjectNumber = 0;
+  AccessSpecifier SubobjectAccess = AS_private;
   for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end();
        Path != PathEnd; ++Path) {
     const CXXBasePathElement &PathElement = Path->back();
 
+    // Pick the best (i.e. most permissive i.e. numerically lowest) access
+    // across all paths.
+    SubobjectAccess = std::min(SubobjectAccess, Path->Access);
+    
     // Determine whether we're looking at a distinct sub-object or not.
     if (SubobjectType.isNull()) {
       // This is the first subobject we've looked at. Record its type.
@@ -1106,7 +1112,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
 
   DeclContext::lookup_iterator I, E;
   for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I)
-    R.addDecl(*I);
+    R.addDecl(*I, std::max(SubobjectAccess, (*I)->getAccess()));
   R.resolveKind();
   return true;
 }
index e3a180a578b9a53ce0121c36cd28c053fa536f1b..c3768b3a7c1038bc86b94882fcdda8b76aa3f29c 100644 (file)
@@ -150,6 +150,7 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
     Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev));
   }
 
+  Typedef->setAccess(D->getAccess());
   Owner->addDecl(Typedef);
 
   return Typedef;
@@ -208,6 +209,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
   if (D->isOutOfLine())
     Var->setLexicalDeclContext(D->getLexicalDeclContext());
 
+  Var->setAccess(D->getAccess());
+
   // FIXME: In theory, we could have a previous declaration for variables that
   // are not static data members.
   bool Redeclaration = false;
@@ -375,6 +378,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
   }
 
   Field->setImplicit(D->isImplicit());
+  Field->setAccess(D->getAccess());
   Owner->addDecl(Field);
 
   return Field;
@@ -559,6 +563,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
     return Inst;
   }
   
+  Inst->setAccess(D->getAccess());
   Owner->addDecl(Inst);
   
   // First, we sort the partial specializations by location, so 
@@ -634,6 +639,8 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
   if (!Instantiated)
     return 0;
 
+  Instantiated->setAccess(D->getAccess());
+
   // Link the instantiated function template declaration to the function
   // template from which it was instantiated.
   FunctionTemplateDecl *InstTemplate 
@@ -964,6 +971,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
   if (D->isPure())
     SemaRef.CheckPureMethod(Method, SourceRange());
 
+  Method->setAccess(D->getAccess());
+
   if (!FunctionTemplate && (!Method->isInvalidDecl() || Previous.empty()) &&
       !Method->getFriendObjectKind())
     Owner->addDecl(Method);