Go to the first, previous, next, last section, table of contents.
The GNU C++ compiler continues to improve and change. A major goal
of our work has been to continue to bring the compiler into compliance
with the draft ANSI C++ standard, and with The Annotated C++
Reference Manual (the ARM). This section outlines most of the
user-noticeable changes that might be encountered during the normal
course of use.
The bulk of this note discusses the cumulative effects of the GNU C++
Renovation Project to date. The work during its most recent phase (1.3)
had these major effects:
- The standard compiler driver
g++
is now the faster compiled
version, rather than a shell script.
- Nested types work much better; notably, nesting is no longer
restricted to nine levels.
- Better ARM conformance on member access control.
- The compiler now always generates default assignment operators
(`operator ='), copy constructors (`X::X(X&)'), and default
constructors (`X::X()') whenever they are required.
- The new draft ANSI standard keyword
mutable
is supported.
- `-fansi-overloading' is the default, to comply better with
the ARM (at some cost in compatibility to earlier versions of GNU C++).
- More informative error messages.
- System include files are automatically treated as if they were
wrapped in `extern "C" { }'.
- The new option `-falt-external-templates' provides alternate
template instantiation semantics.
- Operator declarations are now checked more strictly.
- You can now use template type arguments in the template parameter list.
- You can call the destructor for any type.
- The compiler source code is better organized.
- You can specify where to instantiate template definitions explicitly.
Much of the work in Phase 1.3 went to elimination of known bugs, as well
as the major items above.
During the span of Phase 1.3, there were also two changes associated
with the compiler that, while not specifically part of the C++
Renovation project, may be of interest:
gcov
, a code coverage tool for GNU CC, is now available
from Cygnus Support. (gcov
is free software, but the FSF has not
yet accepted it.) See section `gcov
: a Test Coverage Program' in Using GNU CC, for more information (in Cygnus releases of
that manual).
- GNU C++ now supports signatures, a language extension to
provide more flexibility in abstract type definitions. See section `Type Abstraction using Signatures' in Using GNU CC.
This release includes four wholesale rewrites of certain areas of
compiler functionality:
- Argument matching. GNU C++ is more compliant with the rules
described in Chapter 13, "Overloading", of the ARM. This behavior is
the default, though you can specify it explicitly with
`-fansi-overloading'. For compatibility with earlier releases of
GNU C++, specify `-fno-ansi-overloading'; this makes the compiler
behave as it used to with respect to argument matching and name overloading.
- Default constructors/destructors. Section 12.8 of the ARM, "Copying
Class Objects", and Section 12.1, "Constructors", state that a
compiler must declare such default functions if the user does not
specify them. GNU C++ now declares, and generates when necessary,
the defaults for constructors and destructors you might omit. In
particular, assignment operators (`operator =') behave the same way
whether you define them, or whether the compiler generates them by
default; taking the address of the default `operator =' is now
guaranteed to work. Default copy constructors (`X::X(X&)') now
function correctly, rather than calling the copy assignment operator for
the base class. Finally, constructors (`X::X()'), as well as
assignment operators and copy constructors, are now available whenever
they are required.
- Binary incompatibility. There are no new binary incompatibilities
in Phase 1.3, but Phase 1.2 introduced two binary incompatibilities with
earlier releases. First, the functionality of `operator
new' and `operator delete' changed. Name encoding
("mangling") of virtual table names changed as well. Libraries
built with versions of the compiler earlier than Phase 1.2 must be
compiled with the new compiler. (This includes the Cygnus Q2
progressive release and the FSF 2.4.5 release.)
- New
g++
driver.
A new binary g++
compiler driver replaces the shell script.
The new driver executes faster.
-
The compiler warns when a class contains only private constructors
or destructors, and has no friends. At the request of some of our
customers, we have added a new option, `-Wctor-dtor-privacy' (on by
default), and its negation, `-Wno-ctor-dtor-privacy', to control
the emission of this warning. If, for example, you are working towards
making your code compile warning-free, you can use `-Wall
-Wno-ctor-dtor-privacy' to find the most common warnings.
-
There is now a mechanism which controls exactly when templates are
expanded, so that you can reduce memory usage and program size and also
instantiate them exactly once. You can control this mechanism with the
option `-fexternal-templates' and its corresponding negation
`-fno-external-templates'. Without this feature, space consumed by
template instantiations can grow unacceptably in large-scale projects
with many different source files. The default is
`-fno-external-templates'.
You do not need to use the `-fexternal-templates' option when
compiling a file that does not define and instantiate templates used in
other files, even if those files are compiled with
`-fexternal-templates'. The only side effect is an increase in
object size for each file that was compiled without
`-fexternal-templates'.
When your code is compiled with `-fexternal-templates', all
template instantiations are external; this requires that the templates
be under the control of `#pragma interface' and `#pragma
implementation'. All instantiations that will be needed should be in
the implementation file; you can do this with a
typedef
that
references the instantiation needed. Conversely, when you compile using
the option `-fno-external-templates', all template instantiations are
explicitly internal.
`-fexternal-templates' also allows you to finally separate class
template function definitions from their declarations, thus speeding up
compilation times for every file that includes the template declaration.
Now you can have tens or even hundreds of lines in template
declarations, and thousands or tens of thousands of lines in template
definitions, with the definitions only going through the compiler once
instead of once for each source file. It is important to note that you
must remember to externally instantiate all templates that are
used from template declarations in interface files. If you forget to do
this, unresolved externals will occur.
In the example below, the object file generated (`example.o') will
contain the global instantiation for `Stack<int>'. If other types
of `Stack' are needed, they can be added to `example.cc' or
placed in a new file, in the same spirit as `example.cc'.
foo.h
:
#pragma interface "foo.h"
template<class T>
class Stack {
static int statc;
static T statc2;
Stack() { }
virtual ~Stack() { }
int bar();
};
example.cc
:
#pragma implementation "foo.h"
#include "foo.h"
typedef Stack<int> t;
int Stack<int>::statc;
int Stack<int>::statc2;
int Stack<int>::bar() { }
Note that using `-fexternal-templates' does not reduce memory usage
from completely different instantiations (`Stack<Name>' vs.
`Stack<Net_Connection>'), but only collapses different occurrences
of `Stack<Name>' so that only one `Stack<Name>' is generated.
`-falt-external-templates' selects a slight variation in the
semantics described above (incidentally, you need not specify both
options; `-falt-external-templates' implies
`-fexternal-templates').
With `-fexternal-templates', the compiler emits a definition in the
implementation file that includes the header definition, even if
instantiation is triggered from a different implementation file
(e.g. with a template that uses another template).
With `-falt-external-templates', the definition always goes in the
implementation file that triggers instantiation.
For instance, with these two header files---
`a.h':
#pragma interface
template <class T> class A { ... };
`b.h':
#pragma interface
class B { ... };
void f (A<B>);
Under `-fexternal-templates', the definition of `A<B>' ends up
in the implementation file that includes `a.h'. Under
`-falt-external-templates', the same definition ends up in the
implementation file that includes `b.h'.
-
You can control explicitly where a template is instantiated, without
having to use the template to get an instantiation.
To instantiate a class template explicitly, write `template
class name<paramvals>', where paramvals is a list of values
for the template parameters. For example, you might write
template class A<int>
Similarly, to instantiate a function template explicitly, write
`template fnsign' where fnsign is the particular
function signature you need. For example, you might write
template void foo (int, int)
This syntax for explicit template instantiation agrees with recent
extensions to the draft ANSI standard.
-
The compiler's actions on ANSI-related warnings and errors have
been further enhanced. The `-pedantic-errors' option produces
error messages in a number of new situations: using
return
in a
non-void
function (one returning a value); declaring a local
variable that shadows a parameter (e.g., the function takes an argument
`a', and has a local variable `a'); and use of the `asm'
keyword. Finally, the compiler by default now issues a warning when
converting from an int
to an enumerated type. This is likely to
cause many new warnings in code that hadn't triggered them before. For
example, when you compile this code,
enum boolean { false, true };
void
f ()
{
boolean x;
x = 1; //assigning an int
to an enum
now triggers a warning
}
you should see the warning "anachronistic conversion from integer
type to enumeral type `boolean'
". Instead of assigning the value 1,
assign the original enumerated value `true'.
-
You can now use nested types in a template parameter list, even if the nested
type is defined within the same class that attempts to use the template.
For example, given a template
list
, the following now works:
struct glyph {
...
struct stroke { ... };
list<stroke> l;
...
}
-
Function pointers now work in template parameter lists. For
example, you might want to instantiate a parameterized
list
class
in terms of a pointer to a function like this:
list<int (*)(int, void *)> fnlist;
-
Nested types are now handled correctly. In particular, there is no
longer a limit to how deeply you can nest type definitions.
-
GNU C++ now conforms to the specifications in Chapter 11 of the
ARM, "Member Access Control".
-
The ANSI C++ committee has introduced a new keyword
mutable
.
GNU C++ supports it. Use mutable
to specify that some
particular members of a const
class are not constant. For
example, you can use this to include a cache in a data structure that
otherwise represents a read-only database.
-
Error messages now explicitly specify the declaration, type, or
expression that contains an error.
-
To avoid copying and editing all system include files during GNU
C++ installation, the compiler now automatically recognizes system
include files as C language definitions, as if they were wrapped in
`extern "C" { ... }'.
-
The compiler checks operator declarations more strictly. For example,
you may no longer declare an `operator +' with three arguments.
-
You can now use template type arguments in the same template
parameter list where the type argument is specified (as well as in the
template body). For example, you may write
template <class T, T t> class A { ... };
-
Destructors are now available for all types, even built-in ones; for
example, you can call `int::~int'. (Destructors for types like
int
do not actually do anything, but their existence provides a
level of generality that permits smooth template expansion in more
cases.)
-
Enumerated types declared inside a class are now handled correctly.
-
An argument list for a function may not use an initializer list for its default
value. For example, `void foo ( T x = { 1, 2 } )' is not permitted.
-
A significant amount of work went into improving the ability of the
compiler to act accurately on multiple inheritance and virtual
functions. Virtual function dispatch has been enhanced as well.
-
The warning concerning a virtual inheritance environment with a
non-virtual destructor has been disabled, since it is not clear that
such a warning is warranted.
-
Until exception handling is fully implemented in the Reno-2 release, use
of the identifiers `catch', `throw', or `try' results
in the warning:
t.C:1: warning: `catch', `throw', and `try'
are all C++ reserved words
-
When giving a warning or error concerning initialization of a member in a
class, the compiler gives the name of the member if it has one.
-
Detecting friendship between classes is more accurately checked.
-
The syntaxes of `#pragma implementation "file.h"' and
`#pragma interface' are now more strictly controlled. The compiler
notices (and warns) when any text follows `file.h' in the
implementation pragma, or follows the word `interface'. Any such
text is otherwise ignored.
-
Trying to declare a template on a variable or type is now considered an
error, not an unimplemented feature.
-
When an error occurs involving a template, the compiler attempts to
tell you at which point of instantiation the error occurred, in
addition to noting the line in the template declaration which had the
actual error.
-
The symbol names for function templates in the resulting assembly file
are now encoded according to the arguments, rather than just being
emitted as, for example, two definitions of a function `foo'.
-
Template member functions that are declared
static
no longer
receive a this
pointer.
-
Case labels are no longer allowed to have commas to make up their
expressions.
-
Warnings concerning the shift count of a left or right shift now tell
you if it was a `left' or `right' shift.
-
The compiler now warns when a decimal constant is so large that it
becomes
unsigned
.
-
Union initializers which are raw constructors are now handled properly.
-
The compiler no longer gives incorrect errors when initializing a
union with an empty initializer list.
-
Anonymous unions are now correctly used when nested inside a class.
-
Anonymous unions declared as static class members are now handled
properly.
-
The compiler now notices when a field in a class is declared both as
a type and a non-type.
-
The compiler now warns when a user-defined function shadows a
built-in function, rather than emitting an error.
-
A conflict between two function declarations now produces an error
regardless of their language context.
-
Duplicate definitions of variables with `extern "C"' linkage are no
longer considered in error. (Note in C++ linkage--the default--you may
not have more than one definition of a variable.)
-
Referencing a label that is not defined in any function is now an error.
-
The syntax for pointers to methods has been improved; there are still
some minor bugs, but a number of cases should now be accepted by the
compiler.
-
In error messages, arguments are now numbered starting at 1, instead of
0. Therefore, in the function `void foo (int a, int b)', the
argument `a' is argument 1, and `b' is argument 2. There is
no longer an argument 0.
-
The tag for an enumerator, rather than its value, used as a default
argument is now shown in all error messages. For example, `void
foo (enum x (= true))' is shown instead of `void foo (enum x (=
1))'.
-
The `__asm__' keyword is now accepted by the C++ front-end.
-
Expressions of the form `foo->~Class()' are now handled properly.
-
The compiler now gives better warnings for situations which result in
integer overflows (e.g., in storage sizes, enumerators, unary
expressions, etc).
-
unsigned
bitfields are now promoted to signed int
if the
field isn't as wide as an int
.
-
Declaration and usage of prefix and postfix `operator ++' and
`operator --' are now handled correctly. For example,
class foo
{
public:
operator ++ ();
operator ++ (int);
operator -- ();
operator -- (int);
};
void
f (foo *f)
{
f++; // call f->operator++(int)
++f; // call f->operator++()
f--; // call f->operator++(int)
--f; // call f->operator++()
}
-
In accordance with ARM section 10.1.1, ambiguities and dominance are now
handled properly. The rules described in section 10.1.1 are now fully
implemented.
Two problems remain with regard to debugging:
-
Debugging of anonymous structures on the IBM RS/6000 host is incorrect.
-
Symbol table size is overly large due to redundant symbol information;
this can make
gdb
coredump under certain circumstances. This
problem is not host-specific.
Go to the first, previous, next, last section, table of contents.