On Mon, 18 Nov 2024, Eric Gallager wrote:

> On Fri, Nov 15, 2024 at 11:08 AM Jakub Jelinek <ja...@redhat.com> wrote:
> >
> > Hi!
> >
> > The following patch adds a new tristate option for optimizations related to
> > replaceable global operators new/delete.
> > The option isn't called -fassume-sane-operator-new (which clang++
> > implements), because
> > 1) clang++ option means something different; initially it was an
> >    option to add malloc attribute to those declarations (but we have
> >    malloc attribute on all <new> calls already unconditionally);
> >    later it was changed to add noalias attribute rather than malloc,
> >    whatever it means, but it is certainly about the return value
> >    from the operator new (whether it can alias with other pointers);
> >    we already assume malloc-ish behavior that it doesn't alias any
> >    other pointers
> > 2) the option only affects operator new, we want it affect also
> >    operator delete
> > In the past, before PR101480 fix in 2021, we treated the replaceable
> > global operators new/delete when called from new/delete expressions
> > similarly to malloc/free, i.e. we assumed beyond their described
> > behavior they act like const functions, don't read or modify global
> > state (observable in current TU).  That is fine when we treat
> > malloc/free as a blackbox and hope people don't use malloc hooks or
> > don't do something weird in them, or when the replaceable global
> > operators use new/delete under the hood and don't do anything else
> > (except perhaps throwing exceptions) beyond that.
> > clang++ behavior (again only for replaceable global operators new/delete
> > when called from new/delete expressions (or __builtin_operator_{new,delete})
> > is apparently that they act like pure functions beyond what they are
> > documented to do, i.e. can read global state (aka g++.dg/torture/pr101480.C
> > testcase is considered valid), but can't modify it.
> > I think that is because of the license from
> > https://eel.is/c++draft/expr.new#14
> > https://eel.is/c++draft/expr.delete#6
> > that those calls could be omitted, I think valid C++ programs just can't
> > rely on some observable global state modification done by those operators
> > happening.
> >
> > The patch below makes the clang++ behavior the default (i.e. pure-ish
> > operator new/delete when called from new/delete expressions, no assumptions
> > when called directly) and adds options to override this behavior in both
> > directions, to the pre-PR101480 state with e.g.
> > -fassume-sane-operators-new-delete (in fact a little bit further; because
> > the patch makes those assumptions even when calling the operators directly),
> > and to the current trunk state with e.g.
> > -fno-assume-sane-operators-new-delete.
> >
> > I've tried to explain stuff in the documentation too.
> 
> This all seems excessively complicated; can't it be simplified a bit?

I'd like to second this - I don't see value in adding the "intermediate"
state which we never had.  We for quite some time had two extremes, if
we want to have a separate flag controlling this besides -fallocation-dce
the go with dual-state please.  I'd even say we don't need any new
flag but can use the -fallocation-dce umbrella to control how the
middle-end interprets new/delete semantically since the ability to
elide new/delete implies that the user at least doesn't care about
side-effects.  Documenting the behavior clearly is of course good.

Note I can live with an extra flag, but I can't see good reasons for
the intermediate state.

Richard.

> >
> > So far smoke tested, ok for trunk if it passes full bootstrap/regtest?
> >
> > 2024-11-15  Jakub Jelinek  <ja...@redhat.com>
> >
> >         PR c++/110137
> > gcc/
> >         * doc/invoke.texi (-fassume-sane-operators-new-delete,
> >         -fno-assume-sane-operators-new-delete,
> >         -fassume-sane-operators-new-delete=): Document.
> >         * gimple.cc (gimple_call_fnspec): Handle
> >         -f{,no-}assume-sane-operators-new-delete{,={0,1,2}}.
> > gcc/c-family/
> >         * c.opt (fassume-sane-operators-new-delete,
> >         fassume-sane-operators-new-delete=): New options.
> > gcc/testsuite/
> >         * g++.dg/tree-ssa/pr110137-1.C: New test.
> >         * g++.dg/tree-ssa/pr110137-2.C: New test.
> >         * g++.dg/tree-ssa/pr110137-3.C: New test.
> >         * g++.dg/tree-ssa/pr110137-4.C: New test.
> >         * g++.dg/tree-ssa/pr110137-5.C: New test.
> >         * g++.dg/tree-ssa/pr110137-6.C: New test.
> >
> > --- gcc/c-family/c.opt.jj       2024-11-15 13:13:29.021751829 +0100
> > +++ gcc/c-family/c.opt  2024-11-15 15:35:02.401561741 +0100
> > @@ -1686,6 +1686,14 @@ fasm
> >  C ObjC C++ ObjC++ Var(flag_no_asm, 0)
> >  Recognize the \"asm\" keyword.
> >
> > +fassume-sane-operators-new-delete
> > +C++ ObjC++ LTO Alias(fassume-sane-operators-new-delete=,2,0)
> > +Assume C++ replaceable global operators new, new[], delete, delete[] don't 
> > read or write visible global state.
> > +
> > +fassume-sane-operators-new-delete=
> > +C++ ObjC++ LTO Joined RejectNegative 
> > Var(flag_assume_sane_operators_new_delete) UInteger Init(1) IntegerRange(0, 
> > 2)
> > +Assume C++ replaceable global operators new, new[], delete, delete[] don't 
> > read or write visible global state.
> > +
> >  ; Define extra predefined macros for use in libgcc.
> >  fbuilding-libgcc
> >  C ObjC C++ ObjC++ Undocumented Var(flag_building_libgcc)
> > --- gcc/gimple.cc.jj    2024-11-14 18:26:16.877459015 +0100
> > +++ gcc/gimple.cc       2024-11-15 16:24:13.093917285 +0100
> > @@ -1598,14 +1598,29 @@ gimple_call_fnspec (const gcall *stmt)
> >       such operator, then we can treat it as free.  */
> >    if (fndecl
> >        && DECL_IS_OPERATOR_DELETE_P (fndecl)
> > -      && DECL_IS_REPLACEABLE_OPERATOR (fndecl)
> > -      && gimple_call_from_new_or_delete (stmt))
> > -    return ". o ";
> > +      && DECL_IS_REPLACEABLE_OPERATOR (fndecl))
> > +    {
> > +      if (flag_assume_sane_operators_new_delete == 2)
> > +       return ".co ";
> > +      if (gimple_call_from_new_or_delete (stmt))
> > +       {
> > +         if (flag_assume_sane_operators_new_delete == 1)
> > +           return ".po ";
> > +         return ". o ";
> > +       }
> > +    }
> >    /* Similarly operator new can be treated as malloc.  */
> > -  if (fndecl
> > -      && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (fndecl)
> > -      && gimple_call_from_new_or_delete (stmt))
> > -    return "m ";
> > +  if (fndecl && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (fndecl))
> > +    {
> > +      if (flag_assume_sane_operators_new_delete == 2)
> > +       return "mC";
> > +      if (gimple_call_from_new_or_delete (stmt))
> > +       {
> > +         if (flag_assume_sane_operators_new_delete == 1)
> > +           return "mP";
> > +         return "m ";
> > +       }
> > +    }
> >    return "";
> >  }
> >
> > --- gcc/doc/invoke.texi.jj      2024-11-15 13:13:29.031751688 +0100
> > +++ gcc/doc/invoke.texi 2024-11-15 16:06:17.270100613 +0100
> > @@ -213,7 +213,10 @@ in the following sections.
> >  @item C++ Language Options
> >  @xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
> >  @gccoptlist{-fabi-version=@var{n}  -fno-access-control
> > --faligned-new=@var{n}  -fargs-in-order=@var{n}  -fchar8_t  -fcheck-new
> > +-faligned-new=@var{n}  -fargs-in-order=@var{n}
> > +-fno-assume-sane-operators-new-delete
> > +-fassume-sane-operators-new-delete=@var{n}
> > +-fchar8_t  -fcheck-new
> >  -fconcepts  -fconstexpr-depth=@var{n}  -fconstexpr-cache-depth=@var{n}
> >  -fconstexpr-loop-limit=@var{n}  -fconstexpr-ops-limit=@var{n}
> >  -fno-elide-constructors
> > @@ -3162,6 +3165,48 @@ but few users will need to override the
> >
> >  This flag is enabled by default for @option{-std=c++17}.
> >
> > +@opindex fno-assume-sane-operators-new-delete
> > +@opindex fassume-sane-operators-new-delete
> > +@opindex fassume-sane-operators-new-delete=@var{n}
> > +@item -fno-assume-sane-operators-new
> > +@itemx -fassume-sane-operators-new-delete=@var{n}
> > +The C++ standard allows replacing the global @code{new}, @code{new[]},
> > +@code{delete} and @code{delete[]} operators, though a lot of C++ programs
> > +don't replace them and just use the implementation provided version.
> > +Furthermore, the C++ standard allows omitting those calls if they are
> > +made from new or delete expressions (and by extension the same is
> > +assumed if @code{__builtin_operator_new} or 
> > @code{__builtin_operator_delete}
> > +functions are used).
> > +These options allow control over some optimizations around calls
> > +to those operators.
> > +With @code{-fassume-sane-operators-new-delete} option or equivalent
> > +@code{-fassume-sane-operators-new-delete=2} option GCC may assume that
> > +calls to the replaceable global operators (whether from new or delete
> > +expressions or called directly) don't read or modify any global variables
> > +or variables whose address could escape to the operators (global state;
> > +except for @code{errno} for the @code{new} and @code{new[]} operators).
> > +This allows most optimizations across those calls and is something that
> > +the implementation provided operators satisfy unless @code{malloc}
> > +implementation details are observable in the code or unless @code{malloc}
> > +hooks are used, but might not be satisfied if a program replaces those
> > +operators.
> > +With @code{-fno-assume-sane-operators-new-delete} option or
> > +equivalent @code{-fassume-sane-operators-new-delete=0} option GCC must
> > +assume all these calls (whether from new or delete expressions or called
> > +directly) may read and write global state unless proven otherwise (e.g.@:
> > +when GCC compiles their implementation).  Use these options if those
> > +operators are or may be replaced and code needs to expect such behavior.
> > +With @code{-fassume-sane-operators-new-delete=1} option, which is
> > +the default, GCC must assume reads and writes of global state for
> > +direct calls to these operators, but if those calls are from new or
> > +delete expressions or calls to @code{__builtin_operator_new} or
> > +@code{__builtin_operator_delete}, it may assume global state is not
> > +modified but might be read.  This is because those calls could be
> > +omitted by the implementation and if they would be omitted, code using
> > +new or delete expressions can't rely on global state modifications
> > +happening, while if they are not omitted, the replaced implementation
> > +can still observe global state.
> > +
> >  @opindex fchar8_t
> >  @opindex fno-char8_t
> >  @item -fchar8_t
> > --- gcc/testsuite/g++.dg/tree-ssa/pr110137-1.C.jj       2024-11-15 
> > 16:16:56.296080508 +0100
> > +++ gcc/testsuite/g++.dg/tree-ssa/pr110137-1.C  2024-11-15 
> > 16:30:43.596407861 +0100
> > @@ -0,0 +1,75 @@
> > +// PR c++/110137
> > +// { dg-do compile }
> > +// { dg-options "-O2 -fdump-tree-optimized" }
> > +// { dg-final { scan-tree-dump "j = 2;" "optimized" } } */
> > +// { dg-final { scan-tree-dump "m = 2;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-times "q = 2;" 2 "optimized" } } */
> > +// { dg-final { scan-tree-dump-times "t = 2;" 2 "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "k = 1;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "n = 1;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-times "r = 1;" 2 "optimized" } } */
> > +
> > +int i, j, k, l, m, n, o, q, r, s, t, u;
> > +
> > +void *
> > +foo ()
> > +{
> > +  i = 1;
> > +  j = 2;
> > +  void *p = ::operator new (32);
> > +  j = 3;
> > +  k = i;
> > +  return p;
> > +}
> > +
> > +void
> > +bar (void *p)
> > +{
> > +  l = 1;
> > +  m = 2;
> > +  ::operator delete (p);
> > +  m = 3;
> > +  n = l;
> > +}
> > +
> > +int *
> > +baz ()
> > +{
> > +  o = 1;
> > +  q = 2;
> > +  int *p = new int;
> > +  q = 3;
> > +  r = o;
> > +  return p;
> > +}
> > +
> > +void
> > +qux (int *p)
> > +{
> > +  s = 1;
> > +  t = 2;
> > +  delete p;
> > +  t = 3;
> > +  u = s;
> > +}
> > +
> > +void *
> > +corge ()
> > +{
> > +  o = 1;
> > +  q = 2;
> > +  void *p = __builtin_operator_new (32);
> > +  q = 3;
> > +  r = o;
> > +  return p;
> > +}
> > +
> > +void
> > +waldo (void *p)
> > +{
> > +  s = 1;
> > +  t = 2;
> > +  __builtin_operator_delete (p);
> > +  t = 3;
> > +  u = s;
> > +}
> > --- gcc/testsuite/g++.dg/tree-ssa/pr110137-2.C.jj       2024-11-15 
> > 16:31:18.244919019 +0100
> > +++ gcc/testsuite/g++.dg/tree-ssa/pr110137-2.C  2024-11-15 
> > 16:31:40.919599111 +0100
> > @@ -0,0 +1,75 @@
> > +// PR c++/110137
> > +// { dg-do compile }
> > +// { dg-options "-O2 -fdump-tree-optimized 
> > -fassume-sane-operators-new-delete=1" }
> > +// { dg-final { scan-tree-dump "j = 2;" "optimized" } } */
> > +// { dg-final { scan-tree-dump "m = 2;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-times "q = 2;" 2 "optimized" } } */
> > +// { dg-final { scan-tree-dump-times "t = 2;" 2 "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "k = 1;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "n = 1;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-times "r = 1;" 2 "optimized" } } */
> > +
> > +int i, j, k, l, m, n, o, q, r, s, t, u;
> > +
> > +void *
> > +foo ()
> > +{
> > +  i = 1;
> > +  j = 2;
> > +  void *p = ::operator new (32);
> > +  j = 3;
> > +  k = i;
> > +  return p;
> > +}
> > +
> > +void
> > +bar (void *p)
> > +{
> > +  l = 1;
> > +  m = 2;
> > +  ::operator delete (p);
> > +  m = 3;
> > +  n = l;
> > +}
> > +
> > +int *
> > +baz ()
> > +{
> > +  o = 1;
> > +  q = 2;
> > +  int *p = new int;
> > +  q = 3;
> > +  r = o;
> > +  return p;
> > +}
> > +
> > +void
> > +qux (int *p)
> > +{
> > +  s = 1;
> > +  t = 2;
> > +  delete p;
> > +  t = 3;
> > +  u = s;
> > +}
> > +
> > +void *
> > +corge ()
> > +{
> > +  o = 1;
> > +  q = 2;
> > +  void *p = __builtin_operator_new (32);
> > +  q = 3;
> > +  r = o;
> > +  return p;
> > +}
> > +
> > +void
> > +waldo (void *p)
> > +{
> > +  s = 1;
> > +  t = 2;
> > +  __builtin_operator_delete (p);
> > +  t = 3;
> > +  u = s;
> > +}
> > --- gcc/testsuite/g++.dg/tree-ssa/pr110137-3.C.jj       2024-11-15 
> > 16:31:18.244919019 +0100
> > +++ gcc/testsuite/g++.dg/tree-ssa/pr110137-3.C  2024-11-15 
> > 16:33:16.099256260 +0100
> > @@ -0,0 +1,74 @@
> > +// PR c++/110137
> > +// { dg-do compile }
> > +// { dg-options "-O2 -fdump-tree-optimized 
> > -fassume-sane-operators-new-delete" }
> > +// { dg-final { scan-tree-dump-not "j = 2;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "m = 2;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "q = 2;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "t = 2;" "optimized" } } */
> > +// { dg-final { scan-tree-dump "k = 1;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-times "r = 1;" 2 "optimized" } } */
> > +
> > +int i, j, k, l, m, n, o, q, r, s, t, u;
> > +
> > +void *
> > +foo ()
> > +{
> > +  i = 1;
> > +  j = 2;
> > +  void *p = ::operator new (32);
> > +  j = 3;
> > +  k = i;
> > +  return p;
> > +}
> > +
> > +void
> > +bar (void *p)
> > +{
> > +  l = 1;
> > +  m = 2;
> > +  ::operator delete (p);
> > +  m = 3;
> > +  n = l;
> > +}
> > +
> > +int *
> > +baz ()
> > +{
> > +  o = 1;
> > +  q = 2;
> > +  int *p = new int;
> > +  q = 3;
> > +  r = o;
> > +  return p;
> > +}
> > +
> > +void
> > +qux (int *p)
> > +{
> > +  s = 1;
> > +  t = 2;
> > +  delete p;
> > +  t = 3;
> > +  u = s;
> > +}
> > +
> > +void *
> > +corge ()
> > +{
> > +  o = 1;
> > +  q = 2;
> > +  void *p = __builtin_operator_new (32);
> > +  q = 3;
> > +  r = o;
> > +  return p;
> > +}
> > +
> > +void
> > +waldo (void *p)
> > +{
> > +  s = 1;
> > +  t = 2;
> > +  __builtin_operator_delete (p);
> > +  t = 3;
> > +  u = s;
> > +}
> > --- gcc/testsuite/g++.dg/tree-ssa/pr110137-4.C.jj       2024-11-15 
> > 16:31:18.244919019 +0100
> > +++ gcc/testsuite/g++.dg/tree-ssa/pr110137-4.C  2024-11-15 
> > 16:33:39.034932674 +0100
> > @@ -0,0 +1,74 @@
> > +// PR c++/110137
> > +// { dg-do compile }
> > +// { dg-options "-O2 -fdump-tree-optimized 
> > -fassume-sane-operators-new-delete=2" }
> > +// { dg-final { scan-tree-dump-not "j = 2;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "m = 2;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "q = 2;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "t = 2;" "optimized" } } */
> > +// { dg-final { scan-tree-dump "k = 1;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-times "r = 1;" 2 "optimized" } } */
> > +
> > +int i, j, k, l, m, n, o, q, r, s, t, u;
> > +
> > +void *
> > +foo ()
> > +{
> > +  i = 1;
> > +  j = 2;
> > +  void *p = ::operator new (32);
> > +  j = 3;
> > +  k = i;
> > +  return p;
> > +}
> > +
> > +void
> > +bar (void *p)
> > +{
> > +  l = 1;
> > +  m = 2;
> > +  ::operator delete (p);
> > +  m = 3;
> > +  n = l;
> > +}
> > +
> > +int *
> > +baz ()
> > +{
> > +  o = 1;
> > +  q = 2;
> > +  int *p = new int;
> > +  q = 3;
> > +  r = o;
> > +  return p;
> > +}
> > +
> > +void
> > +qux (int *p)
> > +{
> > +  s = 1;
> > +  t = 2;
> > +  delete p;
> > +  t = 3;
> > +  u = s;
> > +}
> > +
> > +void *
> > +corge ()
> > +{
> > +  o = 1;
> > +  q = 2;
> > +  void *p = __builtin_operator_new (32);
> > +  q = 3;
> > +  r = o;
> > +  return p;
> > +}
> > +
> > +void
> > +waldo (void *p)
> > +{
> > +  s = 1;
> > +  t = 2;
> > +  __builtin_operator_delete (p);
> > +  t = 3;
> > +  u = s;
> > +}
> > --- gcc/testsuite/g++.dg/tree-ssa/pr110137-5.C.jj       2024-11-15 
> > 16:31:18.244919019 +0100
> > +++ gcc/testsuite/g++.dg/tree-ssa/pr110137-5.C  2024-11-15 
> > 16:35:24.354446761 +0100
> > @@ -0,0 +1,76 @@
> > +// PR c++/110137
> > +// { dg-do compile }
> > +// { dg-options "-O2 -fdump-tree-optimized 
> > -fno-assume-sane-operators-new-delete" }
> > +// { dg-final { scan-tree-dump "j = 2;" "optimized" } } */
> > +// { dg-final { scan-tree-dump "m = 2;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-times "q = 2;" 2 "optimized" } } */
> > +// { dg-final { scan-tree-dump-times "t = 2;" 2 "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "k = 1;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "n = 1;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "r = 1;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "u = 1;" "optimized" } } */
> > +
> > +int i, j, k, l, m, n, o, q, r, s, t, u;
> > +
> > +void *
> > +foo ()
> > +{
> > +  i = 1;
> > +  j = 2;
> > +  void *p = ::operator new (32);
> > +  j = 3;
> > +  k = i;
> > +  return p;
> > +}
> > +
> > +void
> > +bar (void *p)
> > +{
> > +  l = 1;
> > +  m = 2;
> > +  ::operator delete (p);
> > +  m = 3;
> > +  n = l;
> > +}
> > +
> > +int *
> > +baz ()
> > +{
> > +  o = 1;
> > +  q = 2;
> > +  int *p = new int;
> > +  q = 3;
> > +  r = o;
> > +  return p;
> > +}
> > +
> > +void
> > +qux (int *p)
> > +{
> > +  s = 1;
> > +  t = 2;
> > +  delete p;
> > +  t = 3;
> > +  u = s;
> > +}
> > +
> > +void *
> > +corge ()
> > +{
> > +  o = 1;
> > +  q = 2;
> > +  void *p = __builtin_operator_new (32);
> > +  q = 3;
> > +  r = o;
> > +  return p;
> > +}
> > +
> > +void
> > +waldo (void *p)
> > +{
> > +  s = 1;
> > +  t = 2;
> > +  __builtin_operator_delete (p);
> > +  t = 3;
> > +  u = s;
> > +}
> > --- gcc/testsuite/g++.dg/tree-ssa/pr110137-6.C.jj       2024-11-15 
> > 16:31:18.244919019 +0100
> > +++ gcc/testsuite/g++.dg/tree-ssa/pr110137-6.C  2024-11-15 
> > 16:35:52.152054593 +0100
> > @@ -0,0 +1,76 @@
> > +// PR c++/110137
> > +// { dg-do compile }
> > +// { dg-options "-O2 -fdump-tree-optimized 
> > -fassume-sane-operators-new-delete=0" }
> > +// { dg-final { scan-tree-dump "j = 2;" "optimized" } } */
> > +// { dg-final { scan-tree-dump "m = 2;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-times "q = 2;" 2 "optimized" } } */
> > +// { dg-final { scan-tree-dump-times "t = 2;" 2 "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "k = 1;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "n = 1;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "r = 1;" "optimized" } } */
> > +// { dg-final { scan-tree-dump-not "u = 1;" "optimized" } } */
> > +
> > +int i, j, k, l, m, n, o, q, r, s, t, u;
> > +
> > +void *
> > +foo ()
> > +{
> > +  i = 1;
> > +  j = 2;
> > +  void *p = ::operator new (32);
> > +  j = 3;
> > +  k = i;
> > +  return p;
> > +}
> > +
> > +void
> > +bar (void *p)
> > +{
> > +  l = 1;
> > +  m = 2;
> > +  ::operator delete (p);
> > +  m = 3;
> > +  n = l;
> > +}
> > +
> > +int *
> > +baz ()
> > +{
> > +  o = 1;
> > +  q = 2;
> > +  int *p = new int;
> > +  q = 3;
> > +  r = o;
> > +  return p;
> > +}
> > +
> > +void
> > +qux (int *p)
> > +{
> > +  s = 1;
> > +  t = 2;
> > +  delete p;
> > +  t = 3;
> > +  u = s;
> > +}
> > +
> > +void *
> > +corge ()
> > +{
> > +  o = 1;
> > +  q = 2;
> > +  void *p = __builtin_operator_new (32);
> > +  q = 3;
> > +  r = o;
> > +  return p;
> > +}
> > +
> > +void
> > +waldo (void *p)
> > +{
> > +  s = 1;
> > +  t = 2;
> > +  __builtin_operator_delete (p);
> > +  t = 3;
> > +  u = s;
> > +}
> >
> >         Jakub
> >
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to