[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