diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-09-09 23:39:55 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-09-09 23:39:55 +0000 |
commit | 9cd9f3f55d22f34f1d69db8bfc2735c4e1e082c3 (patch) | |
tree | b77c90af7e9d34403852e0cb31c84359ef117300 /lib/Sema | |
parent | 3fec4c605e0dd074422bca21626c036f52dab31d (diff) |
For a C++ delete expression where the operand is of class type that
has a single conversion to pointer-to-object type, implicitly convert
to that pointer-to-object type (C++ [expr.delete]p1).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81401 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 43 |
1 files changed, 38 insertions, 5 deletions
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 25dc7691ab..d08d445911 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -717,9 +717,10 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, Action::OwningExprResult Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, bool ArrayForm, ExprArg Operand) { - // C++ 5.3.5p1: "The operand shall have a pointer type, or a class type - // having a single conversion function to a pointer type. The result has - // type void." + // C++ [expr.delete]p1: + // The operand shall have a pointer type, or a class type having a single + // conversion function to a pointer type. The result has type void. + // // DR599 amends "pointer type" to "pointer to object type" in both cases. FunctionDecl *OperatorDelete = 0; @@ -728,8 +729,40 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, if (!Ex->isTypeDependent()) { QualType Type = Ex->getType(); - if (Type->isRecordType()) { - // FIXME: Find that one conversion function and amend the type. + if (const RecordType *Record = Type->getAs<RecordType>()) { + // FIXME: Inherited conversion functions! + llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions; + + OverloadedFunctionDecl *Conversions + = cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions(); + for (OverloadedFunctionDecl::function_iterator + Func = Conversions->function_begin(), + FuncEnd = Conversions->function_end(); + Func != FuncEnd; ++Func) { + // Skip over templated conversion functions; they aren't considered. + if (isa<FunctionTemplateDecl>(*Func)) + continue; + + CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func); + + QualType ConvType = Conv->getConversionType().getNonReferenceType(); + if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>()) + if (ConvPtrType->getPointeeType()->isObjectType()) + ObjectPtrConversions.push_back(Conv); + } + + if (ObjectPtrConversions.size() == 1) { + // We have a single conversion to a pointer-to-object type. Perform + // that conversion. + Operand.release(); + if (PerformImplicitConversion(Ex, + ObjectPtrConversions.front()->getConversionType(), + "converting")) + return ExprError(); + + Operand = Owned(Ex); + Type = Ex->getType(); + } } if (!Type->isPointerType()) |