This is the mail archive of the gcc-prs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

c++/5805: interpretation of the expression new (int*)[10]



>Number:         5805
>Category:       c++
>Synopsis:       the expression 'new (int*)[10]' should be a syntax error
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    unassigned
>State:          open
>Class:          accepts-illegal
>Submitter-Id:   net
>Arrival-Date:   Fri Mar 01 11:36:01 PST 2002
>Closed-Date:
>Last-Modified:
>Originator:     Moritz Franosch
>Release:        3.0.2
>Organization:
Technical University Munich
>Environment:
System: Linux axon 2.4.17 #1 SMP Thu Jan 10 15:29:03 CET 2002 i686 unknown
Architecture: i686

host: i686-pc-linux-gnu
build: i686-pc-linux-gnu
target: i686-pc-linux-gnu
configured with: ../gcc-3.0.2/configure --prefix=/usr/local/gcc-3.0.2
Compiled on SuSE Linux 7.1, kernel 2.4.17.
>Description:

The following code

 start g++-new-bug.cpp
int main() {
  int** p;
  p=new int*[10];     // (1)
  p=new (int*)[10];   // (2)
  p=(new (int*))[10]; // (3)
}
 end g++-new-bug.cpp

if compiled with

g++3 -v g++-new-bug.cpp

generates the output

Reading specs from /usr/local/gcc-3.0.2/lib/gcc-lib/i686-pc-linux-gnu/3.0.2/specs
Configured with: ../gcc-3.0.2/configure --prefix=/usr/local/gcc-3.0.2
Thread model: single
gcc version 3.0.2
 /usr/local/gcc-3.0.2/lib/gcc-lib/i686-pc-linux-gnu/3.0.2/cc1plus -v -iprefix /usr/local/bin/../lib/gcc-lib/i686-pc-linux-gnu/3.0.2/ -D__GNUC__=3 -D__GNUC_MINOR__=0 -D__GNUC_PATCHLEVEL__=2 -D__ELF__ -Dunix -Dlinux -D__ELF__ -D__unix__ -D__linux__ -D__unix -D__linux -Asystem=posix -D__NO_INLINE__ -D__STDC_HOSTED__=1 -D_GNU_SOURCE -Acpu=i386 -Amachine=i386 -Di386 -D__i386 -D__i386__ -D__tune_i686__ -D__tune_pentiumpro__ g++-new-bug.cpp -D__GNUG__=3 -D__GXX_DEPRECATED -D__EXCEPTIONS -D__GXX_ABI_VERSION=100 -quiet -dumpbase g++-new-bug.cpp -version -o /tmp/ccE3jfaX.s
GNU CPP version 3.0.2 (cpplib) (i386 Linux/ELF)
GNU C++ version 3.0.2 (i686-pc-linux-gnu)
	compiled by GNU C version 3.0.2.
ignoring nonexistent directory "/usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.0.2/../../../../include/g++-v3"
ignoring nonexistent directory "/usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.0.2/../../../../include/g++-v3/i686-pc-linux-gnu"
ignoring nonexistent directory "/usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.0.2/../../../../include/g++-v3/backward"
ignoring nonexistent directory "/usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.0.2/include"
ignoring nonexistent directory "/usr/local/lib/gcc-lib/i686-pc-linux-gnu/3.0.2/../../../../i686-pc-linux-gnu/include"
ignoring nonexistent directory "/usr/local/gcc-3.0.2/i686-pc-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/gcc-3.0.2/include/g++-v3
 /usr/local/gcc-3.0.2/include/g++-v3/i686-pc-linux-gnu
 /usr/local/gcc-3.0.2/include/g++-v3/backward
 /usr/local/include
 /usr/local/gcc-3.0.2/lib/gcc-lib/i686-pc-linux-gnu/3.0.2/include
 /usr/include
End of search list.
g++-new-bug.cpp: In function `int main()':
g++-new-bug.cpp:5: cannot convert `int*' to `int**' in assignment

The warning 'g++-new-bug.cpp:5: cannot convert `int*' to `int**' in
assignment' refers to the line marked with '// (3)'. It is correct.

In (1), new allocates an array of 10 pointer to ints, so the return type
is int **.  (3) is equivalent to p=*(new (int*) + 10), so an int * is
assigned to an int ** and thus the warning is correct.

According to the C++ standard (I only have the "November 1997 Draft
C++ Standard"), it seems to me that (2) is a syntax error, but G++
does not report any error. Moreover, I have evidence suggesting that
(2) is compiled semantically equivalent to (1) by g++, which,
according to the standard, can't be. So g++ is not standard compliant
in this case and I consider that to be a bug.

For Intel C++ 5.0.1, (2) is equivalent to (3) (I get the same warning
as with g++, but this time for cases (2) and (3)). Although Intel is
also wrong, switching between different compilers can introduce errors
in programs using statements of the form (2). That's why I chose
medium priority. I would vote for low priority if switching compilers
wasn't an issue.


Here is why (2) can't be equivalent to (1) according to the standard
(g++ thinks it is and thus does not follow the standard):

If (2) would be equivalent to (1), it had to be a new-expression.

A new-expression is

  new-expression:
             ::opt new new-placementopt new-type-id new-initializeropt
             ::opt new new-placementopt ( type-id ) new-initializeropt

For the moment let's take the second rule, so we get

new ( type-id ) new-initializer

But a new-initializer

new-initializer:
             ( expression-listopt )

must start with '(', thus we cannot get 'new (int*)[10]' (2) as a
new-expression in this way.


It remains to substitute new-expression by

new new-type-id


    new-type-id:
             type-specifier-seq new-declaratoropt
    new-declarator:
             ptr-operator new-declaratoropt
             direct-new-declarator
    direct-new-declarator:
             [ expression ]
             direct-new-declarator [ constant-expression ]

We continue with

new type-specifier-seq new-declarator

new type-specifier-seq ptr-operator direct-new-declarator
or
new type-specifier-seq direct-new-declarator

new type-specifier-seq *[10]
or
new type-specifier-seq [10]


     type-specifier-seq:
             type-specifier type-specifier-seqopt
     type-specifier:
             simple-type-specifier
             class-specifier
             enum-specifier
             elaborated-type-specifier
             cv-qualifier
     simple-type-specifier:
             ::opt nested-name-specifieropt type-name
             ::opt nested-name-specifier template template-id
             char
             wchar_t
             bool
             short
             int
             long
             signed
             unsigned
             float
             double
             void
     elaborated-type-specifier:
             class-key ::opt nested-name-specifieropt identifier
             enum ::opt nested-name-specifieropt identifier
             typename ::opt  nested-name-specifier identifier
             typename ::opt  nested-name-specifier templateopt template-id


I can't see a way to get '(int*)' for a type-specifier-seq, so 'new
(int*)[10]' is no new-expression, but 'new (int*)' is and therefore
'new (int*)[10]' (2) can't be interpreted as 'new int*[10]' (1). But
g++ probably treats (1) and (2) as an equivalent new-expression.


Here is why I think (2) must be a syntax error:

If (2) would be an array subscript like (3), we would need a

 postfix-expression:
             primary-expression
             postfix-expression [ expression ]
             ...

We probably need

primary-expression [10]

and have to get from primary-expression to a new-expression, but

 primary-expression:
             literal
             this
             ( expression )
             id-expression

and so we have to use the parentheses '( expression )'. Thus we would
get to '(new (int*))[10]' (3), but never to 'new (int*)[10]' (2).

So (2) isn't a new-expression and it isn't an array subscript. I see
no way to interpret (2) as a C++ construct. But g++ compiles (2)
semantically equivalent to (1) (as a new-expression), which is a bug.



>How-To-Repeat:

See above. Preprocessor is not needed here.


>Fix:

Never use a construct like 'new (int*)[10]' (2) if you intend to
switch from g++ to another compiler.
>Release-Note:
>Audit-Trail:
>Unformatted:


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]