diff options
-rw-r--r-- | include/clang/AST/DeclCXX.h | 17 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 87 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 2 | ||||
-rw-r--r-- | test/SemaCXX/conversion-delete-expr.cpp | 32 |
4 files changed, 93 insertions, 45 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 05244143c3..ada3f18079 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -351,6 +351,10 @@ class CXXRecordDecl : public RecordDecl { /// type (or array thereof), each such class has a trivial destructor. bool HasTrivialDestructor : 1; + /// ComputedVisibleConversions - True when visible conversion functions are + /// already computed and are available. + bool ComputedVisibleConversions : 1; + /// Bases - Base classes of this class. /// FIXME: This is wasted space for a union. CXXBaseSpecifier *Bases; @@ -386,7 +390,9 @@ class CXXRecordDecl : public RecordDecl { /// RecordDecl from which the member class was instantiated. llvm::PointerUnion<ClassTemplateDecl*, CXXRecordDecl*> TemplateOrInstantiation; - + + void getNestedVisibleConversionFunctions(CXXRecordDecl *RD); + protected: CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, @@ -578,17 +584,14 @@ public: /// getVisibleConversionFunctions - get all conversion functions visible /// in current class; including conversion function templates. - OverloadedFunctionDecl *getVisibleConversionFunctions(ASTContext &Context, - CXXRecordDecl *RD); + OverloadedFunctionDecl *getVisibleConversionFunctions(); /// addVisibleConversionFunction - Add a new conversion function to the /// list of visible conversion functions. - void addVisibleConversionFunction(ASTContext &Context, - CXXConversionDecl *ConvDecl); + void addVisibleConversionFunction(CXXConversionDecl *ConvDecl); /// \brief Add a new conversion function template to the list of visible /// conversion functions. - void addVisibleConversionFunction(ASTContext &Context, - FunctionTemplateDecl *ConvDecl); + void addVisibleConversionFunction(FunctionTemplateDecl *ConvDecl); /// addConversionFunction - Add a new conversion function to the /// list of conversion functions. diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 2149005cde..a9eca9b23a 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -33,7 +33,8 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), Abstract(false), HasTrivialConstructor(true), HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true), - HasTrivialDestructor(true), Bases(0), NumBases(0), VBases(0), NumVBases(0), + HasTrivialDestructor(true), ComputedVisibleConversions(false), + Bases(0), NumBases(0), VBases(0), NumVBases(0), Conversions(DC, DeclarationName()), VisibleConversions(DC, DeclarationName()), TemplateOrInstantiation() { } @@ -283,22 +284,12 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, PlainOldData = false; } -/// getVisibleConversionFunctions - get all conversion functions visible -/// in current class; including conversion function templates. -OverloadedFunctionDecl * -CXXRecordDecl::getVisibleConversionFunctions(ASTContext &Context, - CXXRecordDecl *RD) { - if (RD == this) { - // If root class, all conversions are visible. - if (RD->bases_begin() == RD->bases_end()) - return &Conversions; - // If visible conversion list is already evaluated, return it. - if (VisibleConversions.function_begin() - != VisibleConversions.function_end()) - return &VisibleConversions; - } - - QualType ClassType = Context.getTypeDeclType(this); +/// getNestedVisibleConversionFunctions - imports unique conversion +/// functions from base classes into the visible conversion function +/// list of the class 'RD'. This is a private helper method. +void +CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD) { + QualType ClassType = getASTContext().getTypeDeclType(this); if (const RecordType *Record = ClassType->getAs<RecordType>()) { OverloadedFunctionDecl *Conversions = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); @@ -306,24 +297,36 @@ CXXRecordDecl::getVisibleConversionFunctions(ASTContext &Context, Func = Conversions->function_begin(), FuncEnd = Conversions->function_end(); Func != FuncEnd; ++Func) { - if (FunctionTemplateDecl *ConversionTemplate = - dyn_cast<FunctionTemplateDecl>(*Func)) { - RD->addVisibleConversionFunction(Context, ConversionTemplate); - continue; - } - CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func); + NamedDecl *Conv = Func->get(); bool Candidate = true; // Only those conversions not exact match of conversions in current // class are candidateconversion routines. + // FIXME. This is a O(n^2) algorithm. if (RD != this) { OverloadedFunctionDecl *TopConversions = RD->getConversionFunctions(); - QualType ConvType = Context.getCanonicalType(Conv->getType()); + QualType ConvType; + FunctionDecl *FD; + if (FunctionTemplateDecl *ConversionTemplate = + dyn_cast<FunctionTemplateDecl>(Conv)) + FD = ConversionTemplate->getTemplatedDecl(); + else + FD = cast<FunctionDecl>(Conv); + ConvType = getASTContext().getCanonicalType(FD->getType()); + for (OverloadedFunctionDecl::function_iterator TFunc = TopConversions->function_begin(), TFuncEnd = TopConversions->function_end(); TFunc != TFuncEnd; ++TFunc) { - CXXConversionDecl *TopConv = cast<CXXConversionDecl>(*TFunc); - QualType TConvType = Context.getCanonicalType(TopConv->getType()); + + NamedDecl *TopConv = TFunc->get(); + FunctionDecl *TFD; + QualType TConvType; + if (FunctionTemplateDecl *TConversionTemplate = + dyn_cast<FunctionTemplateDecl>(TopConv)) + TFD = TConversionTemplate->getTemplatedDecl(); + else + TFD = cast<FunctionDecl>(TopConv); + TConvType = getASTContext().getCanonicalType(TFD->getType()); if (ConvType == TConvType) { Candidate = false; break; @@ -331,11 +334,11 @@ CXXRecordDecl::getVisibleConversionFunctions(ASTContext &Context, } } if (Candidate) { - if (FunctionTemplateDecl *ConversionTemplate - = Conv->getDescribedFunctionTemplate()) - RD->addVisibleConversionFunction(Context, ConversionTemplate); - else if (!Conv->getPrimaryTemplate()) // ignore specializations - RD->addVisibleConversionFunction(Context, Conv); + if (FunctionTemplateDecl *ConversionTemplate = + dyn_cast<FunctionTemplateDecl>(Conv)) + RD->addVisibleConversionFunction(ConversionTemplate); + else + RD->addVisibleConversionFunction(cast<CXXConversionDecl>(Conv)); } } } @@ -344,7 +347,7 @@ CXXRecordDecl::getVisibleConversionFunctions(ASTContext &Context, E = vbases_end(); VBase != E; ++VBase) { CXXRecordDecl *VBaseClassDecl = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); - VBaseClassDecl->getVisibleConversionFunctions(Context, RD); + VBaseClassDecl->getNestedVisibleConversionFunctions(RD); } for (CXXRecordDecl::base_class_iterator Base = bases_begin(), E = bases_end(); Base != E; ++Base) { @@ -352,19 +355,33 @@ CXXRecordDecl::getVisibleConversionFunctions(ASTContext &Context, continue; CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); - BaseClassDecl->getVisibleConversionFunctions(Context, RD); + BaseClassDecl->getNestedVisibleConversionFunctions(RD); } +} + +/// getVisibleConversionFunctions - get all conversion functions visible +/// in current class; including conversion function templates. +OverloadedFunctionDecl * +CXXRecordDecl::getVisibleConversionFunctions() { + // If root class, all conversions are visible. + if (bases_begin() == bases_end()) + return &Conversions; + // If visible conversion list is already evaluated, return it. + if (ComputedVisibleConversions) + return &VisibleConversions; + getNestedVisibleConversionFunctions(this); + ComputedVisibleConversions = true; return &VisibleConversions; } -void CXXRecordDecl::addVisibleConversionFunction(ASTContext &Context, +void CXXRecordDecl::addVisibleConversionFunction( CXXConversionDecl *ConvDecl) { assert(!ConvDecl->getDescribedFunctionTemplate() && "Conversion function templates should cast to FunctionTemplateDecl."); VisibleConversions.addOverload(ConvDecl); } -void CXXRecordDecl::addVisibleConversionFunction(ASTContext &Context, +void CXXRecordDecl::addVisibleConversionFunction( FunctionTemplateDecl *ConvDecl) { assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) && "Function template is not a conversion function template"); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 0883893a3e..a060e47067 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -739,7 +739,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions; CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); OverloadedFunctionDecl *Conversions = - RD->getVisibleConversionFunctions(Context, RD); + RD->getVisibleConversionFunctions(); for (OverloadedFunctionDecl::function_iterator Func = Conversions->function_begin(), diff --git a/test/SemaCXX/conversion-delete-expr.cpp b/test/SemaCXX/conversion-delete-expr.cpp index bb79fea39f..0a591a285b 100644 --- a/test/SemaCXX/conversion-delete-expr.cpp +++ b/test/SemaCXX/conversion-delete-expr.cpp @@ -43,7 +43,6 @@ void f2 (D2 d) } // Test4 - struct B3 { operator const int *(); }; @@ -69,7 +68,6 @@ struct X { void f4(X x) { delete x; delete x; } // Test6 - struct X1 { operator int(); operator int*(); @@ -78,6 +76,36 @@ struct X1 { void f5(X1 x) { delete x; } // FIXME. May have to issue error here too. +// Test7 +struct Base { + operator int*(); +}; + +struct Derived : Base { + operator int*() const; // not the same function as Base's non-const operator int() +}; + +void foo6(const Derived cd) { + // FIXME. overload resolution must select Derived::operator int*() const; + delete cd; // expected-error {{cannot delete expression of type 'struct Derived const'}} +} + +// Test8 +struct BB { + template<typename T> operator T*() const; +}; + +struct DD : BB { + template<typename T> operator T*() const; // hides base conversion + operator int *() const; +}; + +void foo7 (DD d) +{ + // FIXME. We select DD::operator int *() const; g++ issues ambiguity error. Investigate. + delete d; +} + |