Bug 11228 - [3.3/3.4 regression] ICE on new-expression using array operator new and default-initialization
Summary: [3.3/3.4 regression] ICE on new-expression using array operator new and defau...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.3
: P1 critical
Target Milestone: 3.3.1
Assignee: Matt Austern
URL:
Keywords:
: 11835 (view as bug list)
Depends on:
Blocks:
 
Reported: 2003-06-17 23:15 UTC by Matt Austern
Modified: 2004-01-17 04:22 UTC (History)
3 users (show)

See Also:
Host: i686-pc-linux-gnu/
Target: i686-pc-linux-gnu/
Build: i686-pc-linux-gnu/
Known to work:
Known to fail:
Last reconfirmed: 2003-06-17 23:57:34


Attachments
Proposed patch, including testcases (1.15 KB, patch)
2003-06-19 19:25 UTC, Matt Austern
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Matt Austern 2003-06-17 23:15:27 UTC
Compile the following translation unit with 3.3:
struct MDSWeight { };

void foo(int numWeights)
{
  new MDSWeight[numWeights]();
}

If the compiler is configured with --enable-checking, this causes an internal compiler error:
foo.cc:5: internal compiler error: tree check: expected integer_cst, have 
   non_lvalue_expr in tree_int_cst_lt, at tree.c:3180

If the compiler is configured without checking the behavior is even less friendly: an infinite loop, 
with the compiler allocating more and more memory.

I believe that the code above is legal.  (Although admittedly it would be more natural not to write 
the parentheses.)  The syntax of a new-expression is given in clause 5.3.4, paragraph 1.  
"MDSWeight[numWeights]" is a new-type-id ("MDSWeight" is a type-specifier-seq and 
"[numWeights]" is a direct-new-declarator.  "()" is a valid new-initializer.  Clause 5.3.4, paragraph 
15, describes the semantics of the new-initializer, referring to clause 8.5.  Nothing in 5.3.4/15 or 
8.5 suggests that it's illegal to explicitly request default initialization when using array operator 
new.

Note that the ICE is a regression from 2.95 (which accepts this construct) and from 3.1/3.2 (which 
reject it with an error).
Comment 1 Wolfgang Bangerth 2003-06-17 23:57:34 UTC
Confirmed.

The code is illegal: initializers are not allowed by the standard for array-new
expressions. However, this is a gcc extension.

I thought, this extension was abandoned recently, maybe the infinite loop
is a remnant that wasn't entirely purged.

W.
Comment 2 Matt Austern 2003-06-18 00:07:19 UTC
The infinite loop, by the way, is in build_zero_init:
      for (index = size_zero_node;
	   !tree_int_cst_lt (max_index, index);
	   index = size_binop (PLUS_EXPR, index, size_one_node))
	inits = tree_cons (index,
			   build_zero_init (TREE_TYPE (type),
					    /*nelts=*/NULL_TREE,
					    static_storage_p),
			   inits);
Obviously this won't work if max_index is anything other than an integer constant.
Comment 3 Wolfgang Bangerth 2003-06-18 00:29:01 UTC
I stand corrected on my view that this code is illegal, thanks to an open eye 
by Matt Austern:

On Tuesday 17 June 2003 07:02 pm, Matt Austern wrote:
> You wrote: "The code is illegal: initializers are not allowed by the
> standard for array-new
> expressions."
>
> I'd like that to be true: it would be much easier to reject this
> construct than to deal with it explicitly.  However, I failed to find
> an explicit statement in the standard that said so.  Can you find one?

Uh, Sir, if _you_ don't know then I must be wrong. I know that there used to be
such an extension in gcc, and in the 3.2.3 info pages I find

   The use of initializer lists with new expressions has been
   deprecated, and is now removed from g++.

I seemed to recall that this extension was about this particular case.
However, if I read over the imminent section I can't find anything either. The
standard is pretty vague there, talking only about single objects, not what
initializers should do in the array case (presumably, if that was implied, be
used for _all_ the elements).

So I think I stand corrected -- sorry for spreading confusion :-(
Thanks for having an open eye!
W.

-------------------------------------------------------------------------
Wolfgang Bangerth              email:            bangerth@ices.utexas.edu
                               www: http://www.ices.utexas.edu/~bangerth/
Comment 4 Matt Austern 2003-06-18 04:34:18 UTC
Here's my understanding of 5.3.4/p14: an expression like "new T[n](a,b,c)" is illegal, but an 
expression like "new T[n]()" is legal.  (The former is the gcc extension that Wolfgang was 
referring to.)  The point is that 5.3.4/p14 explicitly distinguishes between a new-initializer of the 
form "()" and one that's non-empty.  It prohibits the latter for array new expressions, but says 
nothing about the former.  And just to make life a little more fun, "new T[n]" and "new T[n]()" don't 
always mean quite the same thing.

I've confirmed my interpretation with the C++ standards committee.
Comment 5 Giovanni Bajo 2003-06-18 09:35:30 UTC
And what would the difference be, between "new T[n]()" and "new T[n]"?
Comment 6 Matt Austern 2003-06-19 04:27:51 UTC
The main difference is that when T is a POD type, new T[n]() default-initializes the members of the 
array but new T[n] leaves them in an indeterminate value.  Probably not an important difference 
most of the time.
Comment 7 Matt Austern 2003-06-19 19:25:40 UTC
Created attachment 4247 [details]
Proposed patch, including testcases
Comment 10 Matt Austern 2003-06-20 19:12:29 UTC
Fix for this bug checked in.
Comment 11 dank 2003-07-19 17:36:22 UTC
The ICE may be fixed, but this test case is now failing at runtime
for me on gcc-ss-20030714 on several platforms unless I link statically.
See PR c++/11309.
Comment 12 Andrew Pinski 2003-08-06 17:58:19 UTC
*** Bug 11835 has been marked as a duplicate of this bug. ***
Comment 13 Paul M. Dubuc 2003-08-06 19:36:59 UTC
I was interested in testing Matt Austern's Comment #6 so I wrote a little test
program.  I took his comment to mean that "new int[n]()" would default
initialize all elements of the array to 0 and "new int[n]" would not.  My test
seem to show that g++ doesn't work this way.  Instead, I would assume that both
work like "new int[n]".  Here's the program:

#include <iostream>

#define SZ 64000

int
main()
{
    int n;
    int* h1 = new int [SZ];
    int* h2 = new int [SZ]();

    for (n = 0; n < SZ; ++n)
    {
        if (h1[n] != h2[n] || h1[n] != 0 || h2[n] != 0)
        {
            std::cout << "h1[" << n << "]=" << std::hex << h1[n] << std::dec;
            std::cout << ' ';
            std::cout << "h2[" << n << "]=" << std::hex << h2[n] << std::dec;
            std::cout << std::endl;
        }
    }
}

When I run this compiled with g++ 2.95.3 I get:

h1[1528]=0 h2[1528]=5f608
h1[1530]=0 h2[1530]=3

When compiled with g++ 3.3 (the bug this report documents for 3.3 doesn't happen
when 'n' is a constant instead of a variable) I get:

h1[1528]=0 h2[1528]=5fb18
h1[1530]=0 h2[1530]=3

This would seem to be the opposite of what I would expect so I commented the
parens out where h2 is allocated and I get the exact same results.

Is there a new bug here?

Comment 14 Andrew Pinski 2003-08-06 19:39:44 UTC
Yes there is bug there but it is already filed in PR11309.