Why the argument of `delete' is converted to void* ?

We have noticed that, in the AST produced by clang, the expression argument of a CXXDeleteExpr node is implicitly converted to void*:

# cat delete.cc
struct S {};

void free(S* ps) {
   delete ps;
}

# llvm/Debug+Asserts/bin/clang -cc1 -ast-dump delete.cc
[...]
void free(S *ps) (CompoundStmt 0x4822650 <delete.cc:3:18, line:5:1>
   (CXXDeleteExpr 0x4822628 <line:4:3, col:10> 'void'
     (ImplicitCastExpr 0x4821df8 <col:10> 'void *' <BitCast>
       (ImplicitCastExpr 0x4821de0 <col:10> 'struct S *' <LValueToRValue>
         (DeclRefExpr 0x4821db8 <col:10> 'struct S *' lvalue ParmVar 0x47eeb20 'ps' 'struct S *')))))

What are the reasons for introducing such an implicit cast?

Enea.

Just a though, but isn't it because the signature of delete is:

operator delete(void *);

Jean-Daniel

I don't think so:

delete ptr;

is something very different from

operator delete(ptr);

I’m not sure it is quite different.

This is the IR generated by clang++ for this code with c++filt _ZdlPv = operator delete(void*):

define void @_Z4freeP1S(%struct.S* %ps) nounwind uwtable ssp {
entry:
%isnull = icmp eq %struct.S* %ps, null
br i1 %isnull, label %delete.end, label %delete.notnull

delete.notnull: ; preds = %entry
%0 = getelementptr inbounds %struct.S* %ps, i64 0, i32 0
tail call void @_ZdlPv(i8* %0) nounwind
br label %delete.end

delete.end: ; preds = %delete.notnull, %entry
ret void
}

declare void @_ZdlPv(i8*) nounwind

– Jean-Daniel

Sorry for the misunderstanding, but the original question was not really meant to be restricted to classes having a trivial destructor (if you add a non-trivial destructor to class S then "delete ps" will call it, whereas "operator delete(ps)" will not).

To rephrase my question: since in the general case "delete ps" may also call the destructor, why is its argument (always) converted to void*?

Cheers,
Enea.

AFAIK, even with a non trivial destructor, the code always end up calling the operator delete(void *) to free the memory.

It will generate something like this:

call the destructor on the struct.
call operator delete((void *)ps);

or in LLVM IR:

tail call void @_ZN1SD1Ev(%struct.S* %ps) nounwind // ps->~S()
%0 = getelementptr inbounds %struct.S* %ps, i64 0, i32 0
tail call void @_ZdlPv(i8* %0) nounwind // operator delete((void *)ps)
br label %delete.end

– Jean-Daniel

[...]

Sorry for the misunderstanding, but the original question was not
really meant to be restricted to classes having a trivial destructor
(if you add a non-trivial destructor to class S then "delete ps" will
call it, whereas "operator delete(ps)" will not).

To rephrase my question: since in the general case "delete ps" may
also call the destructor, why is its argument (always) converted to void*?

Cheers,
Enea.

AFAIK, even with a non trivial destructor, the code always end up
calling the operator delete(void *) to free the memory.

Yes, the argument of "operator delete" has to be converted to a void*.

But this, afaict, is an inner implementation detail that should not be exposed in the AST (or it should be exposed elsewhere, e.g., in a method named getOperatorDeleteArg).

The argument of the CXXDeleteExpr is *not* subject to such an implicit conversion; as a matter of fact, the implicit conversion (if made explicit by the user) would change the semantics of the delete expression by killing the call of the destructor.

Enea.

It's a bug in the AST; Sema is doing an implicit conversion to void* in order
to not have to implement custom logic for deleting values of record type, but
it should at least be dropping the extra ICE when it does so. IR-generation
has to awkwardly work around this.

John.

Can you please review the attached patch?
(It passes all tests in clang.)

Thanks,
Enea.

CXXDeleteExpr.patch (2.62 KB)

How odd. This was done intentionally?

Anyway, approved.

John.