diff options
-rw-r--r-- | clang/include/clang/AST/DeclCXX.h | 22 | ||||
-rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 84 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 6 | ||||
-rw-r--r-- | clang/test/SemaCXX/conversion-delete-expr.cpp | 83 |
4 files changed, 191 insertions, 4 deletions
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 7fd7ee6a3de..05244143c32 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -367,9 +367,15 @@ class CXXRecordDecl : public RecordDecl { /// Conversions - Overload set containing the conversion functions /// of this C++ class (but not its inherited conversion /// functions). Each of the entries in this overload set is a - /// CXXConversionDecl. + /// CXXConversionDecl. OverloadedFunctionDecl Conversions; + /// VisibleConversions - Overload set containing the conversion functions + /// of this C++ class and all those inherited conversion functions that + /// are visible in this class. Each of the entries in this overload set is + /// a CXXConversionDecl or a FunctionTemplateDecl. + OverloadedFunctionDecl VisibleConversions; + /// \brief The template or declaration that this declaration /// describes or was instantiated from, respectively. /// @@ -570,6 +576,20 @@ public: return &Conversions; } + /// getVisibleConversionFunctions - get all conversion functions visible + /// in current class; including conversion function templates. + OverloadedFunctionDecl *getVisibleConversionFunctions(ASTContext &Context, + CXXRecordDecl *RD); + /// addVisibleConversionFunction - Add a new conversion function to the + /// list of visible conversion functions. + void addVisibleConversionFunction(ASTContext &Context, + CXXConversionDecl *ConvDecl); + + /// \brief Add a new conversion function template to the list of visible + /// conversion functions. + void addVisibleConversionFunction(ASTContext &Context, + FunctionTemplateDecl *ConvDecl); + /// addConversionFunction - Add a new conversion function to the /// list of conversion functions. void addConversionFunction(ASTContext &Context, CXXConversionDecl *ConvDecl); diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 073ef947bf8..e878a3df280 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -35,6 +35,7 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true), HasTrivialDestructor(true), Bases(0), NumBases(0), VBases(0), NumVBases(0), Conversions(DC, DeclarationName()), + VisibleConversions(DC, DeclarationName()), TemplateOrInstantiation() { } CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, @@ -282,6 +283,89 @@ 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 visible conversion list is already evaluated, return it. + if (RD == this && + VisibleConversions.function_begin() != VisibleConversions.function_end()) + return &VisibleConversions; + + QualType ClassType = Context.getTypeDeclType(this); + if (const RecordType *Record = ClassType->getAs<RecordType>()) { + OverloadedFunctionDecl *Conversions + = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator + 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); + bool Candidate = true; + // Only those conversions not exact match of conversions in current + // class are candidateconversion routines. + if (RD != this) { + OverloadedFunctionDecl *TopConversions = RD->getConversionFunctions(); + QualType ConvType = Context.getCanonicalType(Conv->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()); + if (ConvType == TConvType) { + Candidate = false; + break; + } + } + } + if (Candidate) { + if (FunctionTemplateDecl *ConversionTemplate + = Conv->getDescribedFunctionTemplate()) + RD->addVisibleConversionFunction(Context, ConversionTemplate); + else if (!Conv->getPrimaryTemplate()) // ignore specializations + RD->addVisibleConversionFunction(Context, Conv); + } + } + } + + for (CXXRecordDecl::base_class_iterator VBase = vbases_begin(), + E = vbases_end(); VBase != E; ++VBase) { + CXXRecordDecl *VBaseClassDecl + = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl()); + VBaseClassDecl->getVisibleConversionFunctions(Context, RD); + } + for (CXXRecordDecl::base_class_iterator Base = bases_begin(), + E = bases_end(); Base != E; ++Base) { + if (Base->isVirtual()) + continue; + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + BaseClassDecl->getVisibleConversionFunctions(Context, RD); + } + return &VisibleConversions; +} + +void CXXRecordDecl::addVisibleConversionFunction(ASTContext &Context, + CXXConversionDecl *ConvDecl) { + assert(!ConvDecl->getDescribedFunctionTemplate() && + "Conversion function templates should cast to FunctionTemplateDecl."); + VisibleConversions.addOverload(ConvDecl); +} + +void CXXRecordDecl::addVisibleConversionFunction(ASTContext &Context, + FunctionTemplateDecl *ConvDecl) { + assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) && + "Function template is not a conversion function template"); + VisibleConversions.addOverload(ConvDecl); +} + void CXXRecordDecl::addConversionFunction(ASTContext &Context, CXXConversionDecl *ConvDecl) { assert(!ConvDecl->getDescribedFunctionTemplate() && diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index edf51cac6e7..c6147ef269b 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -736,11 +736,11 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, QualType Type = Ex->getType(); if (const RecordType *Record = Type->getAs<RecordType>()) { - // FIXME: Inherited conversion functions! llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions; + CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); + OverloadedFunctionDecl *Conversions = + RD->getVisibleConversionFunctions(Context, RD); - OverloadedFunctionDecl *Conversions - = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); for (OverloadedFunctionDecl::function_iterator Func = Conversions->function_begin(), FuncEnd = Conversions->function_end(); diff --git a/clang/test/SemaCXX/conversion-delete-expr.cpp b/clang/test/SemaCXX/conversion-delete-expr.cpp new file mode 100644 index 00000000000..bb79fea39f1 --- /dev/null +++ b/clang/test/SemaCXX/conversion-delete-expr.cpp @@ -0,0 +1,83 @@ +// RUN: clang-cc -fsyntax-only -verify -std=c++0x %s + +// Test1 +struct B { + operator char *(); +}; + +struct D : B { + operator int *(); +}; + +void f (D d) +{ + delete d; // expected-error {{cannot delete expression of type 'struct D'}} +} + +// Test2 +struct B1 { + operator int *(); +}; + +struct D1 : B1 { + operator int *(); +}; + +void f1 (D1 d) +{ + delete d; +} + +// Test3 +struct B2 { + operator const int *(); +}; + +struct D2 : B2 { + operator int *(); +}; + +void f2 (D2 d) +{ + delete d; // expected-error {{cannot delete expression of type 'struct D2'}} +} + +// Test4 + +struct B3 { + operator const int *(); +}; + +struct A3 { + operator const int *(); +}; + +struct D3 : A3, B3 { +}; + +void f3 (D3 d) +{ + delete d; // expected-error {{cannot delete expression of type 'struct D3'}} +} + +// Test5 +struct X { + operator int(); + operator int*(); +}; + +void f4(X x) { delete x; delete x; } + +// Test6 + +struct X1 { + operator int(); + operator int*(); + template<typename T> operator T*() const; // converts to any pointer! +}; + +void f5(X1 x) { delete x; } // FIXME. May have to issue error here too. + + + + |