Fixes problem in finding visible convertion functions of a class

where matching conversion types in base classes were still visible.
Plus refactoring and cleanup.
Added a test case.

llvm-svn: 83485
This commit is contained in:
Fariborz Jahanian 2009-10-07 20:43:36 +00:00
parent 23464866ad
commit 3ee21f1b91
3 changed files with 113 additions and 30 deletions

View File

@ -17,6 +17,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/Decl.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SmallPtrSet.h"
namespace clang {
@ -394,7 +395,11 @@ class CXXRecordDecl : public RecordDecl {
llvm::PointerUnion<ClassTemplateDecl*, CXXRecordDecl*>
TemplateOrInstantiation;
void getNestedVisibleConversionFunctions(CXXRecordDecl *RD);
void getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
const llvm::SmallPtrSet<QualType, 8> &TopConversionsTypeSet,
const llvm::SmallPtrSet<QualType, 8> &HiddenConversionTypes);
void collectConversionFunctions(
llvm::SmallPtrSet<QualType, 8>& ConversionsTypeSet);
protected:
CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,

View File

@ -285,39 +285,45 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
PlainOldData = false;
}
void
CXXRecordDecl::collectConversionFunctions(
llvm::SmallPtrSet<QualType, 8>& ConversionsTypeSet) {
OverloadedFunctionDecl *TopConversions = getConversionFunctions();
for (OverloadedFunctionDecl::function_iterator
TFunc = TopConversions->function_begin(),
TFuncEnd = TopConversions->function_end();
TFunc != TFuncEnd; ++TFunc) {
NamedDecl *TopConv = TFunc->get();
QualType 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) {
CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
const llvm::SmallPtrSet<QualType, 8> &TopConversionsTypeSet,
const llvm::SmallPtrSet<QualType, 8> &HiddenConversionTypes) {
bool inTopClass = (RD == this);
QualType ClassType = getASTContext().getTypeDeclType(this);
if (const RecordType *Record = ClassType->getAs<RecordType>()) {
OverloadedFunctionDecl *Conversions
= cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
llvm::SmallPtrSet<QualType, 8> TopConversionsTypeSet;
bool inTopClass = (RD == this);
if (!inTopClass &&
(Conversions->function_begin() != Conversions->function_end())) {
// populate the TypeSet with the type of current class's conversions.
OverloadedFunctionDecl *TopConversions = RD->getConversionFunctions();
for (OverloadedFunctionDecl::function_iterator
TFunc = TopConversions->function_begin(),
TFuncEnd = TopConversions->function_end();
TFunc != TFuncEnd; ++TFunc) {
NamedDecl *TopConv = TFunc->get();
QualType TConvType;
if (FunctionTemplateDecl *TConversionTemplate =
dyn_cast<FunctionTemplateDecl>(TopConv))
TConvType =
getASTContext().getCanonicalType(
TConversionTemplate->getTemplatedDecl()->getResultType());
else
TConvType =
getASTContext().getCanonicalType(
cast<CXXConversionDecl>(TopConv)->getConversionType());
TopConversionsTypeSet.insert(TConvType);
}
}
for (OverloadedFunctionDecl::function_iterator
Func = Conversions->function_begin(),
@ -336,7 +342,12 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD) {
ConvType =
getASTContext().getCanonicalType(
cast<CXXConversionDecl>(Conv)->getConversionType());
if (inTopClass || !TopConversionsTypeSet.count(ConvType)) {
// 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);
@ -350,7 +361,17 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD) {
E = vbases_end(); VBase != E; ++VBase) {
CXXRecordDecl *VBaseClassDecl
= cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
VBaseClassDecl->getNestedVisibleConversionFunctions(RD);
if (inTopClass)
VBaseClassDecl->getNestedVisibleConversionFunctions(RD,
TopConversionsTypeSet,
TopConversionsTypeSet);
else {
llvm::SmallPtrSet<QualType, 8> HiddenConversionTypes;
collectConversionFunctions(HiddenConversionTypes);
VBaseClassDecl->getNestedVisibleConversionFunctions(RD,
TopConversionsTypeSet,
HiddenConversionTypes);
}
}
for (CXXRecordDecl::base_class_iterator Base = bases_begin(),
E = bases_end(); Base != E; ++Base) {
@ -358,7 +379,17 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD) {
continue;
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
BaseClassDecl->getNestedVisibleConversionFunctions(RD);
if (inTopClass)
BaseClassDecl->getNestedVisibleConversionFunctions(RD,
TopConversionsTypeSet,
TopConversionsTypeSet);
else {
llvm::SmallPtrSet<QualType, 8> HiddenConversionTypes;
collectConversionFunctions(HiddenConversionTypes);
BaseClassDecl->getNestedVisibleConversionFunctions(RD,
TopConversionsTypeSet,
HiddenConversionTypes);
}
}
}
@ -372,7 +403,10 @@ CXXRecordDecl::getVisibleConversionFunctions() {
// If visible conversion list is already evaluated, return it.
if (ComputedVisibleConversions)
return &VisibleConversions;
getNestedVisibleConversionFunctions(this);
llvm::SmallPtrSet<QualType, 8> TopConversionsTypeSet;
collectConversionFunctions(TopConversionsTypeSet);
getNestedVisibleConversionFunctions(this, TopConversionsTypeSet,
TopConversionsTypeSet);
ComputedVisibleConversions = true;
return &VisibleConversions;
}

View File

@ -0,0 +1,44 @@
// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x
struct A {};
struct E {};
struct R {
operator A*();
operator E*();
};
struct S {
operator A*();
operator E*();
};
struct B : R {
operator A*();
};
struct C : B {
};
void foo(C c, int A::* pmf) {
int i = c->*pmf;
}
struct B1 : R, S {
operator A*();
};
struct C1 : B1 {
};
void foo1(C1 c1, int A::* pmf) {
int i = c1->*pmf;
}
void foo1(C1 c1, int E::* pmf) {
// FIXME. Error reporting needs much improvement here.
int i = c1->*pmf; // expected-error {{left hand operand to ->* must be a pointer to class compatible with the right hand operand, but is 'struct C1'}}
}