-
Because cfront does not check the accessibility of types, access errors
for types are issued as warnings instead of errors.
-
A reference to a pointer type may be initialized from a pointer value
without use of a temporary even when the reference pointer type has
additional type qualifiers above those present in the pointer value.
For example,
int *p;
const int *&r = p; // No temporary used
-
No warning is issued when an operator()() function has default
argument expressions.
-
Virtual function table pointer update code is not generated in destructors
for base classes of classes without virtual functions,
even if the base class virtual functions might be overridden in a
further-derived class. For example:
struct A {
virtual void f() {}
A() {}
~A() {}
};
struct B : public A {
B() {}
~B() {f();} // Should call A::f according to ARM 12.7
};
struct C : public B {
void f() {}
} c;
In cfront transition mode, B::~B calls C::f.
-
An alternate form of declaring pointer-to-member-function variables
is supported, namely:
struct A {
void f(int);
static void f(int);
typedef void A::T3(int); // nonstd typedef decl
typedef void T2(int); // std typedef
};
typedef void A::T(int); // nonstd typedef decl
T* pmf = &A::f; // nonstd ptr-to-member decl
A::T2* pf = A::sf; // std ptr to static mem decl
A::T3* pmf2 = &A::f; // nonstd ptr-to-member decl
where T is construed to name a routine type for a nonstatic
member function of class A that takes an int argument
and returns void; the use of such types is restricted to
nonstandard pointer-to-member declarations. The declarations
of T and pmf in combination are equivalent to a single
standard pointer-to-member declaration:
void (A::* pmf)(int) = &A::f;
A nonstandard pointer-to-member declaration that appears outside of a class
declaration, such as the declaration of T, is normally invalid and
would cause an error to be issued. However, for declarations that appear
within a class declaration, such as A::T3, this feature changes the
meaning of a valid declaration. cfront version 2.1 accepts declarations,
such as T, even when A is an incomplete type; so this case is
also excepted.
-
Protected member access checking is not done when the address of a
protected member is taken. For example:
class B { protected: int i; };
class D : public B { void mf()};
void D::mf() {
int B::* pmi1 = &B::i; // error, OK in cfront mode
int D::* pmi2 = &D::i; // OK
}
Note that protected member access checking for other operations (i.e.,
everything except taking a pointer-to-member address) is done
in the normal manner.
-
The destructor of a derived class may implicitly call the private
destructor of a base class. In default mode this is an error but
in cfront mode it is reduced to a warning. For example:
class A {
~A();
};
class B : public A {
~B();
};
B::~B(){} // Error except in cfront mode
-
An extra comma is allowed after the last argument in an argument list,
as for example in
f(1, 2, );
-
When disambiguation requires deciding whether something is a parameter
declaration or an argument expression, the pattern
type-name-or-keyword (identifier...) is treated
as an argument. For example:
class A { A(); };
double d;
A x(int(d));
A (x2);
By default int(d) is interpreted as a parameter declaration
(with redundant parentheses), and so x is a function; but in
cfront transition mode int(d) is an argument and x is
a variable.
The declaration A(x2); is also misinterpreted by cfront.
It should be interpreted as the declaration of an object named x2,
but in cfront mode is interpreted as a function style cast of x2
to the type A.
Similarly, the declaration
int xyz(int() );
declares a function named xyz, that takes a parameter of type
"function taking no arguments and returning an int."
In cfront mode this is interpreted as a declaration of an object that is
initialized with the value int() (which evaluates to zero).
-
A named bit-field may have a size of zero. The declaration is treated
as though no name had been declared.
-
Type qualifiers on the this parameter may to be dropped
in contexts such as this example:
struct A {
void f() const;
};
void (A::*fp)() = &A::f;
This is actually a safe operation. A pointer to a const function
may be put into a pointer to non-const, because a
call using the pointer is permitted to modify the object and the
function pointed to will actually not modify the object. The opposite
assignment would not be safe.
-
Conversion operators specifying conversion to void are allowed.
-
A nonstandard friend declaration may introduce a new type. A friend
declaration that omits the elaborated type specifier is allowed in
default mode, but in cfront mode the declaration is also allowed to
introduce a new type name.
struct A {
friend B;
};
-
The third operator of the ? operator is a conditional expression
instead of an assignment expression as it is in the current
Iso standard.
-
A reference may be initialized with a null.
-
When matching arguments of an overloaded function, a const variable with
value zero is not considered to be a null pointer constant.
-
Plain bit fields (i.e., bit fields declared with a type of int)
are always unsigned.
-
The name given in an elaborated type specifier is permitted to be a
typedef name that is the synonym for a class name, e.g.,
typedef class A T;
class T *pa; // No error in cfront mode
-
No warning is issued on duplicate size and sign specifiers.
short short int i; // No warning in cfront mode
-
A constant pointer-to-member-function may be cast to a pointer-to-function.
A warning is issued.
struct A {int f();};
main () {
int (*p)();
p = (int (*)())A::f; // Okay, with warning
}
-
Arguments of class types that allow bitwise copy construction but also have
destructors are passed by value (i.e., like C structures), and the destructor
is not called on the ``copy.'' In normal mode, the class object is copied
into a temporary, the address of the temporary is passed as the argument,
and the destructor is called on the temporary after the call returns.
Note that because the argument is passed differently (by value instead of
by address), code like this compiled in cfront mode is not calling-sequence
compatible with the same code compiled in normal mode. In practice, this
is not much of a problem, since classes that allow bitwise copying usually
do not have destructors.
-
A union member may be declared to have the type of a class for which the
user has defined an assignment operator (as long as the class has no
constructor or destructor). A warning is issued.
-
When an unnamed class appears in a typedef declaration, the
typedef name may appear as the class name in an elaborated type
specifier.
typedef struct { int i, j; } S;
struct S x; // No error in cfront mode
-
Two member functions may be declared with the same parameter types
when one is static and the other is non-static with a function qualifier.
class A {
void f(int) const;
static void f(int); //No error in cfront mode
-
The scope of a variable in the for-init-statement is the scope
to which the for statement belongs.
int f(int i) {
for (int j = 0; j < i; ++j) {/* ...*/ }
return j; //No error in cfront mode
}
-
Function types differing only in that one is declared extern "C"
and the other extern "C++" can be treated as identical:
typedef void (*PF) ();
extern "C" typedef void (*PCF) ();
void f(PF);
void f(PCF);
PF and PCF are considered identical and void f(PCF)
is treated as a compatible redeclaration of f.
(By contrast, in standard C++ PF and PCF are different and
incompatible types -- PF is a pointer to an extern "C++"
function whereas PCF is a pointer to an extern "C"
function -- and the two declarations of f create an overload set.)
Note that implicit type conversion will always be done between a pointer
to an extern "C" function and a pointer to an extern "C++"
function.
-
Functions declared inline have internal linkage.
-
enum types are regarded as integral types.
-
An uninitialized const object of non-POD class type is allowed
even if its default constructor is implicitly declared:
struct A { virtual void f(); int i; };
const A a;
-
Old-style template specializations are allowed.
-
Old-style guiding declarations for function templates
are allowed.
-
The old-form header <new.h> is available, with its
old definition.
-
operator new returns zero rather than throwing an
exception when no memory is available.
-
In addition, keywords and syntax for the following new
language features are not recognized:
runtime type information
array new and delete
explicit
namespaces
wchar_t
bool
typename
alternative operators
-
An assignment operator declared in a derived class with a parameter
type
matching one of its base classes is treated as a ``default''
assignment
operator --- that is, such a declaration blocks the implicit
generation
of a copy assignment operator. (This is cfront behavior that is known
to
be relied upon in at least one widely used library.) Here's an
example:
struct A { };
struct B : public A {
B& operator=(A&);
};
By default, as well as in cfront-compatibility mode, there will be no
implicit declaration of B::operator=(const B&), whereas in
strict-ISO mode B::operator=(A&) is
not
a copy
assignment
operator and B::operator=(const B&)
is
implicitly
declared.