Edited March, 1994 by Roland Pesch (pesch@cygnus.com
)
Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.
Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided also that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.
Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions.
As you may remember, GNU C++ was the first native-code C++ compiler available under Unix (December 1987). In November 1988, it was judged superior to the AT&T compiler in a Unix World review. In 1990 it won a Sun Observer "Best-Of" award. But now, with new requirements coming out of the ANSI C++ committee and a growing backlog of bugs, it's clear that GNU C++ needs an overhaul.
The C++ language has been under development since 1982. It has evolved significantly since its original incarnation (C with Classes), addressing many commercial needs and incorporating many lessons learned as more and more people started using "object-oriented" programming techniques. In 1989, the first X3J16 committee meeting was held in Washington DC; in the interest of users, C++ was going to be standardized.
As C++ has become more popular, more demands have been placed on its compilers. Some compilers are up to the demands, others are not. GNU C++ was used to prototype several features which have since been incorporated into the standard, most notably exception handling. While GNU C++ has been an excellent experimental vehicle, it did not have the resources that AT&T, Borland, or Microsoft have at their disposal.
We believe that GNU C++ is an important compiler, providing users with many of the features that have made GNU C so popular: fast compilation, good error messages, innovative features, and full sources that may be freely redistributed. The purpose of this overhaul, dubbed the GNU C++ Renovation Project, is to take advantage of the functionality that GNU C++ offers today, to strengthen its base technology, and put it in a position to remain--as other GNU software currently is--the technical leader in the field.
This release represents the latest phase of work in strengthening the compiler on a variety of points. It includes many months of work concentrated on fixing many of the more egregious bugs that presented themselves in the compiler recently. In the coming months, we hope to continue expanding and enhancing the quality and dependability of the industry's only freely redistributable C++ compiler.
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:
g++
is now the faster compiled
version, rather than a shell script.
mutable
is supported.
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).
This release includes four wholesale rewrites of certain areas of compiler functionality:
g++
driver.
A new binary g++
compiler driver replaces the shell script.
The new driver executes faster.
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'.
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.
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 anyou should see the warning "int
to anenum
now triggers a warning }
anachronistic conversion from integer
type to enumeral type `boolean'
". Instead of assigning the value 1,
assign the original enumerated value `true'.
list
, the following now works:
struct glyph { ... struct stroke { ... }; list<stroke> l; ... }
list
class
in terms of a pointer to a function like this:
list<int (*)(int, void *)> fnlist;
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.
template <class T, T t> class A { ... };
int
do not actually do anything, but their existence provides a
level of generality that permits smooth template expansion in more
cases.)
t.C:1: warning: `catch', `throw', and `try' are all C++ reserved words
static
no longer
receive a this
pointer.
unsigned
.
unsigned
bitfields are now promoted to signed int
if the
field isn't as wide as an int
.
class foo { public: operator ++ (); operator ++ (int); operator -- (); operator -- (int); }; void f (foo *f) { f++; // callf->operator++(int)
++f; // callf->operator++()
f--; // callf->operator++(int)
--f; // callf->operator++()
}
Two problems remain with regard to debugging:
gdb
coredump under certain circumstances. This
problem is not host-specific.
The overall goal for the second phase of the GNU C++ Renovation Project is to bring GNU C++ to a new level of reliability, quality, and competitiveness. As particular elements of this strategy, we intend to:
As always, we encourage you to make suggestions and ask questions about GNU C++ as a whole, so we can be sure that the end of this project will bring a compiler that everyone will find essential for C++ and will meet the needs of the world's C++ community.
The C++ template(1) facility, which effectively allows use of variables for types in declarations, is one of the newest features of the language.
GNU C++ is one of the first compilers to implement many of the template facilities currently defined by the ANSI committee.
Nevertheless, the template implementation is not yet complete. This chapter maps the current limitations of the GNU C++ template implementation.
These limitations apply to any use of templates (function templates or class templates) with GNU C++:
Function templates are implemented for the most part. The compiler can correctly determine template parameter values, and will delay instantiation of a function that uses templates until the requisite type information is available.
The following limitations remain:
template <class X> X min (X& x1, X& x2) { ... } int min (int, int); ... int i; short s; min (i, s); // should call min(int,int) // derived from template ...
f
:
template <class T> class A { public: T x; class Y {}; }; template <class X> int f (A<X>::Y y) { ... }
inline
function using templates, the compiler
can only inline the code after the first time you use
that function with whatever particular type signature the template
was instantiated.
Removing this limitation is akin to supporting nested function
definitions in GNU C++; the limitation will probably remain until the
more general problem of nested functions is solved.
enum
type alph
:
template <class T> class list { ... enum alph {a,b,c}; alph bar(); ... }; template <class T> list<int>::alph list<int>::bar() // Syntax error here { ... }
template <class T> class list { ... #ifdef SYSWRONG T x; #endif ... }The preprocessor output leaves sourcefile line number information (lines like `# 6 "foo.cc"' when it expands the
#ifdef
block. These
lines confuse the compiler while parsing templates, giving a syntax
error.
If you cannot avoid preprocessor conditionals in templates, you can
suppress the line number information using the `-P' preprocessor
option (but this will make debugging more difficult), by compiling the
affected modules like this:
g++ -P foo.cc -o foo
Debugging information for templates works for some object code formats, but not others. It works for stabs(2) (used primarily in A.OUT object code, but also in the Solaris 2 version of ELF), and the MIPS version of COFF debugging format.
DWARF support is currently minimal, and requires further development.
These changes in the GNU C++ compiler were made to comply more closely with the ANSI base document, The Annotated C++ Reference Manual (the ARM). Further reducing the divergences from ANSI C++ is a continued goal of the GNU C++ Renovation Project.
Section 3.4, Start and Termination. It is now illegal to take the address of the function `main()'.
Section 4.8, Pointers to Members. The compiler produces an error for trying to convert between a pointer to a member and the type `void *'.
Section 5.2.5, Increment and Decrement. It is an error to use the increment and decrement operators on an enumerated type.
Section 5.3.2, Sizeof. Doing sizeof
on a function is now
an error.
Section 5.3.4, Delete. The syntax of a cast-expression is now more strictly controlled.
Section 7.1.1, Storage Class Specifiers. Using the
static
and extern
specifiers can now only be applied to
names of objects, functions, and anonymous unions.
Section 7.1.1, Storage Class Specifiers. The compiler no longer complains
about taking the address of a variable which has been declared to have register
storage.
Section 7.1.2, Function Specifiers. The compiler produces an
error when the inline
or virtual
specifiers are
used on anything other than a function.
Section 8.3, Function Definitions. It is now an error to shadow a parameter name with a local variable; in the past, the compiler only gave a warning in such a situation.
Section 8.4.1, Aggregates. The rules concerning declaration of an aggregate are now all checked in the GNU C++ compiler; they include having no private or protected members and no base classes.
Section 8.4.3, References. Declaring an array of references is now forbidden. Initializing a reference with an initializer list is also considered an error.
Section 9.5, Unions. Global anonymous unions must be declared
static
.
Section 11.4, Friends. Declaring a member to be a friend of a type that has not yet been defined is an error.
Section 12.1, Constructors. The compiler generates a default copy constructor for a class if no constructor has been declared.
Section 12.6.2, Special Member Functions. When using a
mem-initializer list, the compiler will now initialize class members
in declaration order, not in the order in which you specify them.
Also, the compiler enforces the rule that non-static const
and reference members must be initialized with a mem-initializer
list when their class does not have a constructor.
Section 12.8, Copying Class Objects. The compiler generates default copy constructors correctly, and supplies default assignment operators compatible with user-defined ones.
Section 13.4, Overloaded Operators. An overloaded operator may no longer have default arguments.
Section 13.4.4, Function Call. An overloaded `operator ()' must be a non-static member function.
Section 13.4.5, Subscripting. An overloaded `operator []' must be a non-static member function.
Section 13.4.6, Class Member Access. An overloaded `operator ->' must be a non-static member function.
Section 13.4.7, Increment and Decrement. The compiler will now
make sure a postfix `operator ++' or `operator --' has an
int
as its second argument.
In order to support its strong typing rules and the ability to provide function overloading, the C++ programming language encodes information about functions and objects, so that conflicts across object files can be detected during linking. (3) These rules tend to be unique to each individual implementation of C++.
The scheme detailed in the commentary for 7.2.1 of The Annotated
Reference Manual offers a description of a possible implementation
which happens to closely resemble the cfront
compiler. The
design used in GNU C++ differs from this model in a number of ways:
void
, char
, short
,
int
, long
, float
, double
, and long
double
, GNU C++ supports two additional types: wchar_t
, the wide
character type, and long long
(if the host supports it). The
encodings for these are `w' and `x' respectively.
3foo
for the foo
class
constructor). Destructors are encoded as two leading underscores
separated by either a period or a dollar sign, depending on the
capabilities of the local host, followed by the encoded name. For
example, the destructor `foo::~foo' is encoded as `_$_3foo'.
foo
is `__vt$foo', and the table for foo::bar
is
named `__vt$foo$bar'.
foo
contains a static member `bar', its
encoding would be `_3foo$bar'.
int
s would result in
using three letters, instead of just `ii').