diff options
| -rw-r--r-- | clang/include/clang/AST/DeclCXX.h | 14 | ||||
| -rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 229 | ||||
| -rw-r--r-- | clang/test/CXX/class.access/p4.cpp | 44 | 
3 files changed, 165 insertions, 122 deletions
| diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 5abc1224d77..6b04ed54109 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -329,12 +329,6 @@ class CXXRecordDecl : public RecordDecl {    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 @@ public:    /// 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); diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index cc743200b12..6deadcce547 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -318,105 +318,128 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,    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; -  llvm::SmallPtrSet<CanQualType, 8> ConversionFunctions; -  if (!inTopClass) -    collectConversionFunctions(ConversionFunctions); +    AccessSpecifier BaseAccess +      = CXXRecordDecl::MergeAccess(Access, I->getAccessSpecifier()); +    bool BaseInVirtual = InVirtual || I->isVirtual(); -  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)); -    } +    CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl()); +    CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess, +                              *HiddenTypes, Output, VOutput, 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)); -    } +/// 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); +  } + +  // 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 @@ const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() {    // 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);  } diff --git a/clang/test/CXX/class.access/p4.cpp b/clang/test/CXX/class.access/p4.cpp index 7aa614cd8b1..e397db126c8 100644 --- a/clang/test/CXX/class.access/p4.cpp +++ b/clang/test/CXX/class.access/p4.cpp @@ -112,3 +112,47 @@ namespace test3 {      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; } +} | 

