This is the mail archive of the
gcc-prs@gcc.gnu.org
mailing list for the GCC project.
c++/5805: interpretation of the expression new (int*)[10]
- From: jfranosc at ph dot tum dot de
- To: gcc-gnats at gcc dot gnu dot org
- Date: Fri, 1 Mar 2002 20:31:41 +0100
- Subject: 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: