diff options
author | John McCall <rjmccall@apple.com> | 2010-03-15 09:07:48 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-03-15 09:07:48 +0000 |
commit | b05b5f35f114505182b076aa70002843c0669beb (patch) | |
tree | c51ebfbec65f77de50a87f948485aa59837ec0be | |
parent | 51f4c940d5fa5183fafac68d6be1ba3cf974934b (diff) |
Remember access paths for visible conversion decls.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98539 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/DeclCXX.h | 14 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 229 | ||||
-rw-r--r-- | test/CXX/class.access/p4.cpp | 44 |
3 files changed, 165 insertions, 122 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 5abc1224d7..6b04ed5410 100644 --- a/include/clang/AST/DeclCXX.h +++ b/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/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index cc743200b1..6deadcce54 100644 --- a/lib/AST/DeclCXX.cpp +++ b/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/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp index 7aa614cd8b..e397db126c 100644 --- a/test/CXX/class.access/p4.cpp +++ b/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; } +} |