From: Fariborz Jahanian Date: Wed, 7 Oct 2009 20:43:36 +0000 (+0000) Subject: Fixes problem in finding visible convertion functions of a class X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0351a1e2e17c1edf27f90c23fbf65d8fcad995c4;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@83485 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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 TemplateOrInstantiation; - void getNestedVisibleConversionFunctions(CXXRecordDecl *RD); + void getNestedVisibleConversionFunctions(CXXRecordDecl *RD, + const llvm::SmallPtrSet &TopConversionsTypeSet, + const llvm::SmallPtrSet &HiddenConversionTypes); + void collectConversionFunctions( + llvm::SmallPtrSet& 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& 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(TopConv)) + TConvType = + getASTContext().getCanonicalType( + TConversionTemplate->getTemplatedDecl()->getResultType()); + else + TConvType = + getASTContext().getCanonicalType( + cast(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 &TopConversionsTypeSet, + const llvm::SmallPtrSet &HiddenConversionTypes) { + bool inTopClass = (RD == this); QualType ClassType = getASTContext().getTypeDeclType(this); if (const RecordType *Record = ClassType->getAs()) { OverloadedFunctionDecl *Conversions = cast(Record->getDecl())->getConversionFunctions(); - llvm::SmallPtrSet 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(TopConv)) - TConvType = - getASTContext().getCanonicalType( - TConversionTemplate->getTemplatedDecl()->getResultType()); - else - TConvType = - getASTContext().getCanonicalType( - cast(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(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(Conv)) RD->addVisibleConversionFunction(ConversionTemplate); @@ -350,7 +361,17 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD) { E = vbases_end(); VBase != E; ++VBase) { CXXRecordDecl *VBaseClassDecl = cast(VBase->getType()->getAs()->getDecl()); - VBaseClassDecl->getNestedVisibleConversionFunctions(RD); + if (inTopClass) + VBaseClassDecl->getNestedVisibleConversionFunctions(RD, + TopConversionsTypeSet, + TopConversionsTypeSet); + else { + llvm::SmallPtrSet 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(Base->getType()->getAs()->getDecl()); - BaseClassDecl->getNestedVisibleConversionFunctions(RD); + if (inTopClass) + BaseClassDecl->getNestedVisibleConversionFunctions(RD, + TopConversionsTypeSet, + TopConversionsTypeSet); + else { + llvm::SmallPtrSet 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 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'}} +}