Comeau C++ 4.0
Dialects and Modes
C++ Language Accepted
  1. C++ Dialect Accepted

    The front end accepts the C++ language as defined by The Annotated C++ Reference Manual (ARM) by Ellis and Stroustrup, Addison-Wesley, 1990, including templates, exceptions, and the anachronisms of Chapter 18. Most features have been updated to match the specification in the ANSI/ISO X3J16/WG21 Working Paper.

    The front end also has a cfront compatibility mode, which duplicates a number of "features" and bugs of cfront 2.1 and 3.0.x. Complete compatibility is not guaranteed or intended-the mode is there to allow programmers who have used cfront features to continue to compile their existing code. In particular, if a program gets an error when compiled by cfront, the Comeau C++ 4.0 front end may produce a different error or no error at all.

    Command-line options are also available to enable and disable anachronisms and strict standard-conformance checking.

  2. New Language Features Accepted

    The following features not in the ARM but in the ANSI/ISO X3J16/WG21 Working Paper are accepted:

    1. The dependent statement of an if, while, do-while, or for is considered to be a scope, and the restriction on having such a dependent statement be a declaration is removed.

    2. The expression tested in an if, while, do-while, or for, as the first operand of a "?" operator, or as an operand of the "&&", "||", or "!" operators may have a pointer-to-member type or a class type that can be converted to a pointer-to-member type in addition to the scalar cases permitted by the ARM.

    3. Qualified names are allowed in elaborated type specifiers.

    4. A global-scope qualifier is allowed in member references of the form x.::A::B and also in cases such as p->::A::B.

    5. The precedence of the third operand of the "?" operator is changed.

    6. If control reaches the end of the main() routine, and main() has an integral return type, it is treated as if a return 0; statement were executed.

    7. Pointers to arrays with unknown bounds as parameter types are diagnosed as errors.

    8. A functional-notation cast of the form A() can be used even if A is a class without a (nontrivial) constructor. The temporary created gets the same default initialization to zero as a static object of the class type.

    9. A cast can be used to select one out of a set of overloaded functions when taking the address of a function.

    10. Template friend declarations and definitions are permitted in class definitions and class template definitions.

    11. Type template parameters are permitted to have default arguments.

    12. Function templates may have nontype template parameters.

    13. A reference to const volatile cannot be bound to an rvalue.

    14. Qualification conversions such as conversion from T** to T const * const * are allowed.

    15. Digraphs are recognized.

    16. Operator keywords (e.g., and, bitand, etc.) are recognized.

    17. Static data member declarations can be used to declare member constants.

    18. wchar_t is recognized as a keyword and a distinct type.

    19. bool is recognized.

    20. RTTI (runtime type identification), including dynamic_cast and the typeid operator, is implemented.

    21. Declarations in tested conditions (in if, switch, for, and while statements) are supported.

    22. Array new and delete are implemented.

    23. New-style casts (static_cast, reinterpret_cast, and const_cast) are implemented.

    24. Definition of a nested class outside its enclosing class is allowed.

    25. mutable is accepted on nonstatic data member declarations.

    26. Namespaces are implemented, including using declarations and directives. Access declarations are broadened to match the corresponding using declarations.

    27. Explicit instantiation of templates is implemented.

    28. The typename keyword is recognized.

    29. explicit is accepted to declare non-converting constructors.

    30. The scope of a variable declared in the for-init-statement of a for loop is the scope of the loop (not the surrounding scope).

    31. Member templates are implemented.

    32. The new specialization syntax (using "template <>") is implemented.

    33. Cv-qualifiers are retained on rvalues (in particular, on function return values).

    34. The distinction between trivial and nontrivial constructors has been implemented, as has the distinction between PODs and non-PODs with trivial constructors.

    35. The linkage specification is treated as part of the function type (affecting function overloading and implicit conversions).

    36. extern inline functions are supported, and the default linkage for inline functions is external.

    37. a typedef name may be used in an explicit destructor call.

  3. New Language Features Not Accepted

    The following features not in the ARM but in the X3J16/WG21 Working Paper are not accepted:

    1. Virtual functions in derived classes may not return a type that is the derived-class version of the type returned by the overridden function in the base class. This is expected to appear in the next upgrade.

    2. enum types are not considered to be non-integral types.

    3. It is not possible to overload operators using functions that take enum types and no class types.

    4. The new lookup rules for member references of the form x.A::B and p->A::B are not yet implemented.

    5. enum types cannot contain values larger than can be contained in an int.

    6. reinterpret_cast does not allow casting a pointer to member of one class to a pointer to member of another class if the classes are unrelated.

    7. Explicit qualification of template functions is not implemented.

    8. Name binding in templates in the style of N0288/93-0081 is not implemented.

    9. In a reference of the form f()->g(), with g a static member function, f() is not evaluated. This is as required by the ARM. The WP, however, requires that f() be evaluated.

    10. Class name injection is not implemented.

    11. Overloading of function templates (partial specialization) is not implemented.

    12. Partial specialization of class templates is not implemented. This is expect to appear in the next upgrade.

    13. Placement delete is not implemented. This is expected to appear in the next upgrade.

    14. Putting a try/catch around the initializers and body of a constructor is not implemented.

    15. The notation :: template (and ->template, etc.) is not implemented.

    16. Template template parameters are not implemented.

    17. Certain restrictions are not yet enforced on the use of (pointer-to-)function types that involve exception-specifications.

  4. Anachronisms Accepted

    The following anachronisms are accepted when anachronisms are enabled:

    1. overload is allowed in function declarations. It is accepted and ignored.

    2. Definitions are not required for static data members that can be initialized using default initialization. The anachronism does not apply to static data members of template classes; they must always be defined.

    3. The number of elements in an array may be specified in an array delete operation. The value is ignored.

    4. A single operator++() and operator--() function can be used to overload both prefix and postfix operations.

    5. The base class name may be omitted in a base class initializer if there is only one immediate base class.

    6. Assignment to this in constructors and destructors is allowed. This is allowed only if anachronisms are enabled and the "assignment to this" configuration parameter is enabled.

    7. A bound function pointer (a pointer to a member function for a given object) can be cast to a pointer to a function.

    8. A nested class name may be used as a nonnested class name provided no other class of that name has been declared. The anachronism is not applied to template classes.

    9. A reference to a non-const type may be initialized from a value of a different type. A temporary is created, it is initialized from the (converted) initial value, and the reference is set to the temporary.

    10. A reference to a non-const class type may be initialized from an rvalue of the class type or a derived class thereof. No (additional) temporary is used.

    11. A function with old-style parameter declarations is allowed and may participate in function overloading as though it were prototyped. Default argument promotion is not applied to parameter types of such functions when the check for compatibility is done, so that the following declares the overloading of two functions named f:

      int f(int);
      int f(x) char x; { return x; } 

      It will be noted that in C this code is legal but has a different meaning: a tentative declaration of f is followed by its definition.

    12. When --nonconst_ref_anachronism is enabled, a reference to a nonconst class can be bound to a class rvalue of the same type or a derived type thereof.
      struct A {
      	  A operator=(A&);
      	  A operator+(const A&);
      int main () {
      	  A b(1);
      	  b = A(1) + A(2);   // Allowed as anachronism
                return 0;

  5. Extensions Accepted in Normal C++ Mode

    The following extensions are accepted in all modes (except when strict ANSI violations are diagnosed as errors):

    1. A friend declaration for a class may omit the class keyword:
      class B;
      class A {
      	  friend B;  // Should be "friend class B"

    2. Constants of scalar type may be defined within classes (this is an old form; the modern form uses an initialized static data member):
      class A {
      	  const int size = 10;
      	  int a[size];

    3. In the declaration of a class member, a qualified name may be used:
      struct A { 
      	  int A::f();  // Should be int f(); 

    4. operator()() functions may have default argument expressions. A warning is issued.

    5. The preprocessing symbol c_plusplus is defined in addition to the standard __cplusplus.

    6. An extension is supported to allow an anonymous union to be introduced into a containing class by a typedef name - it needn't be declared directly, as with a true anonymous union. For example:
      typedef union {
      	  int i, j;
      } U;            // U identifies a reusable anonymous union.
      class A {
      	  U;// Okay -- references to A::i and A::j are allowed.

      In addition, the extension also permits "anonymous classes" and "anonymous structs," as long as they have no C++ features (e.g., no static data members or member functions and no nonpublic members) and have no nested types other than other anonymous classes, structs, or unions. For instance,

      struct A {
      	  struct {
      	    int i, j;
      	  };// Okay -- references to A::i and A::j are allowed.

      This extension is only enabled in a custom porting arrangement.

    7. The NCEG proposed extension for C (see below) is itself extended to allow restrict as a type qualifier for reference and pointer-to-member types and for nonstatic member functions. The set of C++ extensions is described in X3J16/92-0057.

    8. 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-ANSI mode B::operator=(A&) is not a copy assignment operator and B::operator=(const B&) is implicitly declared.

    9. Implicit type conversion between a pointer to an extern "C" function and a pointer to an extern "C++" function is permitted. Here's an example:
      extern "C" void f();// f's type has extern "C" linkage
      void (*pf)()        // pf points to an extern "C++" function
      	    = &f;// error unless implicit conversion is allowed 

      This extension is allowed in environments where C and C++ functions share the same calling conventions. This extension is enabled by default only through a custom porting arrangement; it can also be enabled in cfront-compatibility mode or with command-line option --implicit_extern_c_type_conversion. It is disabled in strict-ANSI mode.

    Except where noted, all of the extensions described in the C dialect section are also allowed in C++ mode.

  6. Extensions Accepted in Cfront 2.1 Compatibility Mode

    The following extensions are accepted in cfront 2.1 compatibility mode in addition to the extensions listed in the 2.1/ 3.0 section following (i.e., these are things that were corrected in the 3.0 release of cfront):

    1. The dependent statement of an if, while, do-while, or for is not considered to define a scope. The dependent statement may not be a declaration. Any objects constructed within the dependent statement are destroyed at exit from the dependent statement.

    2. Implicit conversion from integral types to enumeration types is allowed.

    3. A non-const member function may be called for a const object. A warning is issued.

    4. A const void * value may be implicitly converted to a void * value, e.g., when passed as an argument.

    5. When, in determining the level of argument match for overloading, a reference parameter is initialized from an argument that requires a non-class standard conversion, the conversion counts as a user-defined conversion. (This is an outright bug, which unfortunately happens to be exploited in the NIH class libraries.)

    6. When a builtin operator is considered alongside overloaded operators in overload resolution, the match of an operand of a builtin type against the builtin type required by the builtin operator is considered a standard conversion in all cases (e.g., even when the type is exactly right without conversion).

    7. A reference to a non-const type may be initialized from a value that is a const-qualified version of the same type, but only if the value is the result of selecting a member from a const class object or a pointer to such an object.

    8. The cfront 2.1 "transitional model" for nested type support is simulated. In the transitional model a nested type is promoted to the file scope unless a type of the same name already exists at the file scope. It is an error to have two nested classes of the same name that need to be promoted to file scope or to define a type at file scope after the declaration of a nested class of the same name. This "feature" actually restricts the source language accepted by the compiler. This is necessary because of the affect this feature has on the name mangling of functions that use nested types in their signature. This feature does not apply to template classes and is only enabled when cfront 2.1 object code compatibility is available.

    9. A cast to an array type is allowed; it is treated like a cast to a pointer to the array element type. A warning is issued.

    10. When an array is selected from a class, the type qualifiers on the class object (if any) are not preserved in the selected array. (In the normal mode, any type qualifiers on the object are preserved in the element type of the resultant array.)

    11. An identifier in a function is allowed to have the same name as a parameter of the function. A warning is issued.

    12. A value may be supplied on the return statement in a function with a void return type. A warning is issued.

    13. Cfront has a bug that causes a global identifier to be found when a member of a class or one of its base classes should actually be found. This bug is emulated in cfront compatibility mode. A warning is issued when, because of this feature, a nonstandard lookup is performed.

      The following conditions must be satisfied for the nonstandard lookup to be performed:

      1. A member in a base class must have the same name as an identifier at the global scope. The member may be a function, static data member, or nonstatic data member. Member type names don't apply because a nested type will be promoted to the global scope by cfront which disallows a later declaration of a type with the same name at the global scope.

      2. The declaration of the global scope name must occur between the declaration of the derived class and the declaration of an out-of-line constructor or destructor. The global scope name must be a type name.

      3. No other member function definition-even one for an unrelated class-may appear between the destructor and the offending reference. This has the effect that the nonstandard lookup applies to only one class at any given point in time. For example:

        struct B   {
        	void func(const char*);
        struct D : public B {
             void Init(const char* );
        struct func {
        	func( const char* msg);
        void D::Init(const char* t)
        	// Should call B::func --
        	// calls func::func instead.
        	new func(t);

        The global scope name must be present in a base class (B::func in this example) for the nonstandard lookup to occur. Even if the derived class were to have a member named func, it is still the presence of B::func that determines how the lookup will be performed.

    14. A parameter of type "const void *" is allowed on operator delete; it is treated as equivalent to "void *".

    15. A period (".") may be used for qualification where "::" should be used. Only "::" may be used as a global qualifier. Except for the global qualifier, the two kinds of qualifier operators may not be mixed in a given name (i.e., you may say A::B::C or A.B.C but not A::B.C or A.B::C). A period may not be used in a vacuous destructor reference nor in a qualifier that follows a template reference such as A<T>::B.

    16. Cfront 2.1 does not correctly look up names in friend functions that are inside class definitions. In this example function f should refer to the functions and variables (e.g., f1 and a1) from the class declaration. Instead, the global definitions are used.
      	 int a1;
      	 int e1;
      	 void f1();
      	 class A {
      	  int a1;
      	  void f1();
      	  friend void f()
      	    int i1 = a1;   // cfront uses global a1
      	    f1();          // cfront uses global f1

      Only the innermost class scope is (incorrectly) skipped by cfront as illustrated in the following example.

      	 int a1;
      	 int b1;
      	 struct A {
      	   static int a1;
      	   class B {
      	     static int b1;
      	     friend void f()
      	       int i1 = a1;  // cfront uses A::a1
      	       int j1 = b1;  // cfront uses global b1

    17. operator= may be declared as a nonmember function. (This is flagged as an anachronism by cfront 2.1)

    18. A type qualifier is allowed (but ignored) on the declaration of a constructor or destructor. For example:
      class A {
      	  A() const;         // No error in cfront 2.1 mode

  7. Extensions Accepted in Cfront 2.1 and 3.0 Compatibility Mode

    The following extensions are accepted in both cfront 2.1 and cfront 3.0 compatibility mode (i.e., these are features or problems that exist in both cfront 2.1 and 3.0):

    1. 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.

    2. Conversion operators specifying conversion to void are allowed.

    3. 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; 

    4. The third operand of the "?" operator is a conditional expression instead of an assignment expression as it is in the current X3J16/WG21 Working Paper.

    5. 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 

    6. A reference may be initialized with a null.

    7. Because cfront does not check the accessibility of types, access errors for types are issued as warnings instead of errors.

    8. When matching arguments of an overloaded function, a const variable with value zero is not considered to be a null pointer constant. In general, in overload resolution a null pointer constant must be spelled "0" to be considered a null pointer constant (e.g., '\0' is not considered a null pointer constant).

    9. No warning is issued when an operator()() function has default argument expressions.

    10. An alternate form of declaring pointer-to-member-function variables is supported, namely:
      	 struct A {
      	   void f(int);
      	   static void sf(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.

    11. 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.

    12. 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 { 
      	 class B : public A { 
      	 B::~B(){}    // Error except in cfront mode 

    13. 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));

      By default int(d) is interpreted as a parameter declaration (with redundant parentheses), and so x is a function; but in cfront-compatibility 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).

    14. A named bit-field may have a size of zero. The declaration is treated as though no name had been declared.

    15. Plain bit fields (i.e., bit fields declared with a type of int) are always unsigned.

    16. 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 

    17. No warning is issued on duplicate size and sign specifiers.
      short short int i;         // No warning in cfront mode 

    18. 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 compatibility mode, B::~B calls C::f.

    19. An extra comma is allowed after the last argument in an argument list, as for example in
      f(1, 2, ); 

    20. A constant pointer-to-member-function may be cast to a pointer-to-function. A warning is issued.
      	 struct A {int f();};
      	 int main () {
      	  int (*p)();
      	  p = (int (*)())A::f;  // Okay, with warning
                return 0;

    21. 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.

    22. 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.

    23. 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 

    24. Two member functions may be declared with the same parameter types when one is static and the other is nonstatic with a function qualifier.
      	  class A {
      	  void f(int) const;
      	  static void f(int);      // No error in cfront mode

    25. The scope of a variable declared 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

    26. 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.)

      It is possible in cfront-compatibility mode an implicit type conversion will always be done between a pointer to an extern "C" function and a pointer to an extern "C++" function. This extension would have to be enable via a custom porting arrangement.

    27. Functions declared inline have internal linkage.

    (c)© 1997-2013 Comeau Computing, EDG. All rights reserved.

    Comeau Computing
    91-34 120th Street
    Richmond Hill, NY 11418-3214

    Back to documentation Table of Contents
    /* the end */