forked from OSchip/llvm-project
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:
parent
23464866ad
commit
3ee21f1b91
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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'}}
|
||||
}
|
Loading…
Reference in New Issue