On Mon, Apr 25, 2016 at 9:57 PM, Jason Merrill <ja...@redhat.com> wrote: > Hmm, this seems to assume that operator delete itself doesn't do > anything with the object being deleted. This is true of the default > implementation, but I don't see anything in the standard that > prohibits a user-supplied replacement or class-specific deallocation > function from accessing the memory.
Hmm, but the delete expression invokes the (default) destructor which ends the lifetime of the object and thus invalidates all memory. Don't we place a CLOBBER there as well nowadays (seems not). For struct A { A(); ~A(); int i; }; int main() { A *a = new A; delete a; } I see struct A * a; <<cleanup_point <<< Unknown tree: expr_stmt (void) (a = TARGET_EXPR <D.2346, operator new (4)>;, try { A::A ((struct A *) D.2346); } catch { operator delete (D.2346); }, (struct A *) D.2346;) >>>>>; <<cleanup_point <<< Unknown tree: expr_stmt if (SAVE_EXPR <a> != 0B) { A::~A (SAVE_EXPR <a>);, operator delete ((void *) SAVE_EXPR <a>);; } else { <<< Unknown tree: void_cst >>> } >>>>>; so after the destructor is invoked the objects lifetime ends. Richard. > Jason > > > On Mon, Apr 25, 2016 at 6:08 AM, Richard Biener > <richard.guent...@gmail.com> wrote: >> On Fri, Apr 22, 2016 at 11:37 PM, Mikhail Maltsev <malts...@gmail.com> wrote: >>> On 04/20/2016 05:12 PM, Richard Biener wrote: >>>> You have >>>> >>>> +static tree >>>> +handle_free_attribute (tree *node, tree name, tree /*args*/, int >>>> /*flags*/, >>>> + bool *no_add_attrs) >>>> +{ >>>> + tree decl = *node; >>>> + if (TREE_CODE (decl) == FUNCTION_DECL >>>> + && type_num_arguments (TREE_TYPE (decl)) != 0 >>>> + && POINTER_TYPE_P (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl))))) >>>> + DECL_ALLOC_FN_KIND (decl) = ALLOC_FN_FREE; >>>> + else >>>> + { >>>> + warning_at (DECL_SOURCE_LOCATION (decl), OPT_Wattributes, >>>> + "%qE attribute ignored", name); >>>> + *no_add_attrs = true; >>>> + } >>>> >>>> so one can happily apply the attribute to >>>> >>>> void foo (void *, void *); >>>> >>>> but then >>>> >>>> @@ -2117,6 +2127,13 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref) >>>> /* Fallthru to general call handling. */; >>>> } >>>> >>>> + if (callee != NULL_TREE >>>> + && (flags_from_decl_or_type (callee) & ECF_FREE) != 0) >>>> + { >>>> + tree ptr = gimple_call_arg (call, 0); >>>> + return ptr_deref_may_alias_ref_p_1 (ptr, ref); >>>> + } >>>> >>>> will ignore the 2nd argument. I think it's better to ignore the attribute >>>> if type_num_arguments () != 1. >>> >>> Actually, the C++ standard ([basic.stc.dynamic]/2) defines the following 4 >>> deallocation functions implicitly: >>> >>> void operator delete(void*); >>> void operator delete[](void*); >>> void operator delete(void*, std::size_t) noexcept; >>> void operator delete[](void*, std::size_t) noexcept; >>> >>> And the standard library also has: >>> >>> void operator delete(void*, const std::nothrow_t&); >>> void operator delete[](void*, const std::nothrow_t&); >>> void operator delete(void*, std::size_t, const std::nothrow_t&); >>> void operator delete[](void*, std::size_t, const std::nothrow_t&); >>> >>> IIUC, 'delete(void*, std::size_t)' is used by default in C++14 >>> (https://gcc.gnu.org/ml/gcc-patches/2014-12/msg01266.html). How should we >>> handle >>> this? >> >> Hmm. I guess by adjusting the documentation of the attribute to >> explicitely mention >> the behavior on the rest of the argument pointed-to memory (the >> function is assumed >> to neither write nor read from that memory). Also explicitely mention >> that 'this' is >> always the first argument if present. >> >> Richard. >> >>> -- >>> Regards, >>> Mikhail Maltsev