diff options
-rw-r--r-- | include/clang/AST/DeclCXX.h | 7 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 92 | ||||
-rw-r--r-- | test/SemaCXX/builtin-ptrtomember-overload-1.cpp | 44 |
3 files changed, 113 insertions, 30 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 4038fe6081..ee6314cc36 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -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, diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index d1aef6a5b3..7408f2fc60 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -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; } diff --git a/test/SemaCXX/builtin-ptrtomember-overload-1.cpp b/test/SemaCXX/builtin-ptrtomember-overload-1.cpp new file mode 100644 index 0000000000..304e8d1398 --- /dev/null +++ b/test/SemaCXX/builtin-ptrtomember-overload-1.cpp @@ -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'}} +} |