[cfe-commits] r98539 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/DeclCXX.cpp test/CXX/class.access/p4.cpp

John McCall rjmccall at apple.com
Mon Mar 15 02:07:48 PDT 2010


Author: rjmccall
Date: Mon Mar 15 04:07:48 2010
New Revision: 98539

URL: http://llvm.org/viewvc/llvm-project?rev=98539&view=rev
Log:
Remember access paths for visible conversion decls.


Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/test/CXX/class.access/p4.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=98539&r1=98538&r2=98539&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Mon Mar 15 04:07:48 2010
@@ -329,12 +329,6 @@
   llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*>
     TemplateOrInstantiation;
   
-  void getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
-          const llvm::SmallPtrSet<CanQualType, 8> &TopConversionsTypeSet,
-          const llvm::SmallPtrSet<CanQualType, 8> &HiddenConversionTypes);
-  void collectConversionFunctions(
-    llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) const;
-  
 protected:
   CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
                 SourceLocation L, IdentifierInfo *Id,
@@ -559,14 +553,6 @@
   /// in current class; including conversion function templates.
   const UnresolvedSetImpl *getVisibleConversionFunctions();
 
-  /// addVisibleConversionFunction - Add a new conversion function to the
-  /// list of visible conversion functions.
-  void addVisibleConversionFunction(CXXConversionDecl *ConvDecl);
-  
-  /// \brief Add a new conversion function template to the list of visible
-  /// conversion functions.
-  void addVisibleConversionFunction(FunctionTemplateDecl *ConvDecl);
-  
   /// addConversionFunction - Add a new conversion function to the
   /// list of conversion functions.
   void addConversionFunction(CXXConversionDecl *ConvDecl);

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=98539&r1=98538&r2=98539&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Mon Mar 15 04:07:48 2010
@@ -318,105 +318,128 @@
   data().PlainOldData = false;
 }
 
-void
-CXXRecordDecl::collectConversionFunctions(
-                 llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) const
-{
-  const UnresolvedSetImpl *Cs = getConversionFunctions();
-  for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end();
-         I != E; ++I) {
-    NamedDecl *TopConv = *I;
-    CanQualType TConvType;
-    if (FunctionTemplateDecl *TConversionTemplate =
-        dyn_cast<FunctionTemplateDecl>(TopConv))
-      TConvType = 
-        getASTContext().getCanonicalType(
-                    TConversionTemplate->getTemplatedDecl()->getResultType());
-    else 
-      TConvType = 
-        getASTContext().getCanonicalType(
-                      cast<CXXConversionDecl>(TopConv)->getConversionType());
-    ConversionsTypeSet.insert(TConvType);
-  }  
-}
-
-/// getNestedVisibleConversionFunctions - imports unique conversion 
-/// functions from base classes into the visible conversion function
-/// list of the class 'RD'. This is a private helper method.
-/// TopConversionsTypeSet is the set of conversion functions of the class
-/// we are interested in. HiddenConversionTypes is set of conversion functions
-/// of the immediate derived class which  hides the conversion functions found 
-/// in current class.
-void
-CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
-                const llvm::SmallPtrSet<CanQualType, 8> &TopConversionsTypeSet,                               
-                const llvm::SmallPtrSet<CanQualType, 8> &HiddenConversionTypes) 
-{
-  bool inTopClass = (RD == this);
-  QualType ClassType = getASTContext().getTypeDeclType(this);
-  if (const RecordType *Record = ClassType->getAs<RecordType>()) {
-    const UnresolvedSetImpl *Cs
-      = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
-    
-    for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end();
-           I != E; ++I) {
-      NamedDecl *Conv = *I;
-      // Only those conversions not exact match of conversions in current
-      // class are candidateconversion routines.
-      CanQualType ConvType;
-      if (FunctionTemplateDecl *ConversionTemplate = 
-            dyn_cast<FunctionTemplateDecl>(Conv))
-        ConvType = 
-          getASTContext().getCanonicalType(
-                      ConversionTemplate->getTemplatedDecl()->getResultType());
-      else
-        ConvType = 
-          getASTContext().getCanonicalType(
-                          cast<CXXConversionDecl>(Conv)->getConversionType());
-      // We only add conversion functions found in the base class if they
-      // are not hidden by those found in HiddenConversionTypes which are
-      // the conversion functions in its derived class.
-      if (inTopClass || 
-          (!TopConversionsTypeSet.count(ConvType) && 
-           !HiddenConversionTypes.count(ConvType)) ) {
-        if (FunctionTemplateDecl *ConversionTemplate =
-              dyn_cast<FunctionTemplateDecl>(Conv))
-          RD->addVisibleConversionFunction(ConversionTemplate);
+static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
+  QualType T;
+  if (FunctionTemplateDecl *ConvTemp = dyn_cast<FunctionTemplateDecl>(Conv))
+    T = ConvTemp->getTemplatedDecl()->getResultType();
+  else 
+    T = cast<CXXConversionDecl>(Conv)->getConversionType();
+  return Context.getCanonicalType(T);
+}
+
+/// Collect the visible conversions of a base class.
+///
+/// \param Base a base class of the class we're considering
+/// \param InVirtual whether this base class is a virtual base (or a base
+///   of a virtual base)
+/// \param Access the access along the inheritance path to this base
+/// \param ParentHiddenTypes the conversions provided by the inheritors
+///   of this base
+/// \param Output the set to which to add conversions from non-virtual bases
+/// \param VOutput the set to which to add conversions from virtual bases
+/// \param HiddenVBaseCs the set of conversions which were hidden in a
+///   virtual base along some inheritance path
+static void CollectVisibleConversions(ASTContext &Context,
+                                      CXXRecordDecl *Record,
+                                      bool InVirtual,
+                                      AccessSpecifier Access,
+                  const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes,
+                                      UnresolvedSetImpl &Output,
+                                      UnresolvedSetImpl &VOutput,
+                           llvm::SmallPtrSet<NamedDecl*, 8> &HiddenVBaseCs) {
+  // The set of types which have conversions in this class or its
+  // subclasses.  As an optimization, we don't copy the derived set
+  // unless it might change.
+  const llvm::SmallPtrSet<CanQualType, 8> *HiddenTypes = &ParentHiddenTypes;
+  llvm::SmallPtrSet<CanQualType, 8> HiddenTypesBuffer;
+
+  // Collect the direct conversions and figure out which conversions
+  // will be hidden in the subclasses.
+  UnresolvedSetImpl &Cs = *Record->getConversionFunctions();
+  if (!Cs.empty()) {
+    HiddenTypesBuffer = ParentHiddenTypes;
+    HiddenTypes = &HiddenTypesBuffer;
+
+    for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I) {
+      bool Hidden =
+        !HiddenTypesBuffer.insert(GetConversionType(Context, I.getDecl()));
+
+      // If this conversion is hidden and we're in a virtual base,
+      // remember that it's hidden along some inheritance path.
+      if (Hidden && InVirtual)
+        HiddenVBaseCs.insert(cast<NamedDecl>(I.getDecl()->getCanonicalDecl()));
+
+      // If this conversion isn't hidden, add it to the appropriate output.
+      else if (!Hidden) {
+        AccessSpecifier IAccess
+          = CXXRecordDecl::MergeAccess(Access, I.getAccess());
+
+        if (InVirtual)
+          VOutput.addDecl(I.getDecl(), IAccess);
         else
-          RD->addVisibleConversionFunction(cast<CXXConversionDecl>(Conv));
+          Output.addDecl(I.getDecl(), IAccess);
       }
     }
   }
 
-  if (getNumBases() == 0 && getNumVBases() == 0)
-    return;
+  // Collect information recursively from any base classes.
+  for (CXXRecordDecl::base_class_iterator
+         I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) {
+    const RecordType *RT = I->getType()->getAs<RecordType>();
+    if (!RT) continue;
+
+    AccessSpecifier BaseAccess
+      = CXXRecordDecl::MergeAccess(Access, I->getAccessSpecifier());
+    bool BaseInVirtual = InVirtual || I->isVirtual();
+
+    CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl());
+    CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess,
+                              *HiddenTypes, Output, VOutput, HiddenVBaseCs);
+  }
+}
 
-  llvm::SmallPtrSet<CanQualType, 8> ConversionFunctions;
-  if (!inTopClass)
-    collectConversionFunctions(ConversionFunctions);
-
-  for (CXXRecordDecl::base_class_iterator VBase = vbases_begin(),
-       E = vbases_end(); VBase != E; ++VBase) {
-    if (const RecordType *RT = VBase->getType()->getAs<RecordType>()) {
-      CXXRecordDecl *VBaseClassDecl
-        = cast<CXXRecordDecl>(RT->getDecl());
-      VBaseClassDecl->getNestedVisibleConversionFunctions(RD,
-                    TopConversionsTypeSet,
-                    (inTopClass ? TopConversionsTypeSet : ConversionFunctions));
-    }
+/// Collect the visible conversions of a class.
+///
+/// This would be extremely straightforward if it weren't for virtual
+/// bases.  It might be worth special-casing that, really.
+static void CollectVisibleConversions(ASTContext &Context,
+                                      CXXRecordDecl *Record,
+                                      UnresolvedSetImpl &Output) {
+  // The collection of all conversions in virtual bases that we've
+  // found.  These will be added to the output as long as they don't
+  // appear in the hidden-conversions set.
+  UnresolvedSet<8> VBaseCs;
+  
+  // The set of conversions in virtual bases that we've determined to
+  // be hidden.
+  llvm::SmallPtrSet<NamedDecl*, 8> HiddenVBaseCs;
+
+  // The set of types hidden by classes derived from this one.
+  llvm::SmallPtrSet<CanQualType, 8> HiddenTypes;
+
+  // Go ahead and collect the direct conversions and add them to the
+  // hidden-types set.
+  UnresolvedSetImpl &Cs = *Record->getConversionFunctions();
+  Output.append(Cs.begin(), Cs.end());
+  for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I)
+    HiddenTypes.insert(GetConversionType(Context, I.getDecl()));
+
+  // Recursively collect conversions from base classes.
+  for (CXXRecordDecl::base_class_iterator
+         I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) {
+    const RecordType *RT = I->getType()->getAs<RecordType>();
+    if (!RT) continue;
+
+    CollectVisibleConversions(Context, cast<CXXRecordDecl>(RT->getDecl()),
+                              I->isVirtual(), I->getAccessSpecifier(),
+                              HiddenTypes, Output, VBaseCs, HiddenVBaseCs);
   }
-  for (CXXRecordDecl::base_class_iterator Base = bases_begin(),
-       E = bases_end(); Base != E; ++Base) {
-    if (Base->isVirtual())
-      continue;
-    if (const RecordType *RT = Base->getType()->getAs<RecordType>()) {
-      CXXRecordDecl *BaseClassDecl
-        = cast<CXXRecordDecl>(RT->getDecl());
-
-      BaseClassDecl->getNestedVisibleConversionFunctions(RD,
-                    TopConversionsTypeSet,
-                    (inTopClass ? TopConversionsTypeSet : ConversionFunctions));
-    }
+
+  // Add any unhidden conversions provided by virtual bases.
+  for (UnresolvedSetIterator I = VBaseCs.begin(), E = VBaseCs.end();
+         I != E; ++I) {
+    if (!HiddenVBaseCs.count(cast<NamedDecl>(I.getDecl()->getCanonicalDecl())))
+      Output.addDecl(I.getDecl(), I.getAccess());
   }
 }
 
@@ -429,37 +452,27 @@
   // If visible conversion list is already evaluated, return it.
   if (data().ComputedVisibleConversions)
     return &data().VisibleConversions;
-  llvm::SmallPtrSet<CanQualType, 8> TopConversionsTypeSet;
-  collectConversionFunctions(TopConversionsTypeSet);
-  getNestedVisibleConversionFunctions(this, TopConversionsTypeSet,
-                                      TopConversionsTypeSet);
+  CollectVisibleConversions(getASTContext(), this, data().VisibleConversions);
   data().ComputedVisibleConversions = true;
   return &data().VisibleConversions;
 }
 
-void CXXRecordDecl::addVisibleConversionFunction(
-                                          CXXConversionDecl *ConvDecl) {
-  assert(!ConvDecl->getDescribedFunctionTemplate() &&
-         "Conversion function templates should cast to FunctionTemplateDecl.");
-  data().VisibleConversions.addDecl(ConvDecl);
-}
-
-void CXXRecordDecl::addVisibleConversionFunction(
-                                          FunctionTemplateDecl *ConvDecl) {
-  assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
-         "Function template is not a conversion function template");
-  data().VisibleConversions.addDecl(ConvDecl);
-}
-
 void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) {
   assert(!ConvDecl->getDescribedFunctionTemplate() &&
          "Conversion function templates should cast to FunctionTemplateDecl.");
+  assert(ConvDecl->getDeclContext() == this &&
+         "conversion function does not belong to this record");
+
+  // We intentionally don't use the decl's access here because it
+  // hasn't been set yet.  That's really just a misdesign in Sema.
   data().Conversions.addDecl(ConvDecl);
 }
 
 void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) {
   assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
          "Function template is not a conversion function template");
+  assert(ConvDecl->getDeclContext() == this &&
+         "conversion function does not belong to this record");
   data().Conversions.addDecl(ConvDecl);
 }
 

Modified: cfe/trunk/test/CXX/class.access/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/p4.cpp?rev=98539&r1=98538&r2=98539&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/p4.cpp (original)
+++ cfe/trunk/test/CXX/class.access/p4.cpp Mon Mar 15 04:07:48 2010
@@ -112,3 +112,47 @@
     A local; // expected-error {{'~A' is a private member}}
   }
 }
+
+// Conversion functions.
+namespace test4 {
+  class Base {
+  private:
+    operator Private(); // expected-note 4 {{declared private here}}
+  public:
+    operator Public();
+  };
+
+  class Derived1 : private Base { // expected-note 2 {{declared private here}} \
+                                  // expected-note {{constrained by private inheritance}}
+    Private test1() { return *this; } // expected-error {{'operator Private' is a private member}}
+    Public test2() { return *this; }
+  };
+  Private test1(Derived1 &d) { return d; } // expected-error {{'operator Private' is a private member}} \
+                                           // expected-error {{cannot cast 'test4::Derived1' to its private base class}}
+  Public test2(Derived1 &d) { return d; } // expected-error {{cannot cast 'test4::Derived1' to its private base class}} \
+                                          // expected-error {{'operator Public' is a private member}}
+
+
+  class Derived2 : public Base {
+    Private test1() { return *this; } // expected-error {{'operator Private' is a private member}}
+    Public test2() { return *this; }
+  };
+  Private test1(Derived2 &d) { return d; } // expected-error {{'operator Private' is a private member}}
+  Public test2(Derived2 &d) { return d; }
+
+  class Derived3 : private Base { // expected-note {{constrained by private inheritance here}} \
+                                  // expected-note {{declared private here}}
+  public:
+    operator Private();
+  };
+  Private test1(Derived3 &d) { return d; }
+  Public test2(Derived3 &d) { return d; } // expected-error {{'operator Public' is a private member of 'test4::Base'}} \
+                                          // expected-error {{cannot cast 'test4::Derived3' to its private base class}}
+
+  class Derived4 : public Base {
+  public:
+    operator Private();
+  };
+  Private test1(Derived4 &d) { return d; }
+  Public test2(Derived4 &d) { return d; }
+}





More information about the cfe-commits mailing list