C H A P T E R  4

Language Extensions

The -features=extensions option enables you to compile nonstandard code that is commonly accepted by other C++ compilers. You can use this option when you must compile invalid code and you are not permitted to modify the code to make it valid.

This chapter describes the language extensions that the compiler supports when you use the -features=extensions options.



Note - You can easily turn each supported instance of invalid code into valid code that all compilers will accept. If you are allowed to make the code valid, you should do so instead of using this option. Using the -features=extensions option perpetuates invalid code that will be rejected by some compilers.




4.1 Overriding With Less Restrictive Virtual Functions

The C++ standard says that an overriding virtual function must not be less restrictive in the exceptions it allows than any function it overrides. It can have the same restrictions or be more restrictive. Note that the absence of an exception specification allows any exception.

Suppose, for example, that you call a function through a pointer to a base class. If the function has an exception specification, you can count on no other exceptions being thrown. If the overriding function has a less-restrictive specification, an unexpected exception could be thrown, which can result in bizarre program behavior followed by a program abort. This is the reason for the rule.

When you use -features=extensions, the compiler will allow overriding functions with less-restrictive exception specifications.


4.2 Making Forward Declarations of enum Types and Variables

When you use -features=extensions, the compiler allows the forward declaration of enum types and variables. In addition, the compiler allows the declaration of a variable with an incomplete enum type. The compiler will always assume an incomplete enum type to have the same size and range as type int on the current platform.

The following two lines show an example of invalid code that will compile when you use the -features=extensions option.

enum E; // invalid: forward declaration of enum not allowed
E e;    // invalid: type E is incomplete

Because enum definitions cannot reference one another, and no enum definition can cross-reference another type, the forward declaration of an enumeration type is never necessary. To make the code valid, you can always provide the full definition of the enum before it is used.



Note - On 64-bit architectures, it is possible for an enum to require a size that is larger than type int. If that is the case, and if the forward declaration and the definition are visible in the same compilation, the compiler will emit an error. If the actual size is not the assumed size and the compiler does not see the discrepancy, the code will compile and link, but might not run properly. Mysterious program behavior can occur, particularly if an 8-byte value is stored in a 4-byte variable.




4.3 Using Incomplete enum Types

When you use -features=extensions, incomplete enum types are taken as forward declarations. For example, the following invalid code will compile when you use the -features=extensions option.

typedef enum E F; // invalid, E is incomplete

As noted previously, you can always include the definition of an enum type before it is used.


4.4 Using an enum Name as a Scope Qualifier

Because an enum declaration does not introduce a scope, an enum name cannot be used as a scope qualifier. For example, the following code is invalid.

enum E { e1, e2, e3 };
int i = E::e1; // invalid: E is not a scope name

To compile this invalid code, use the -features=extensions option. The -features=extensions option instructs the compiler to ignore a scope qualifier if it is the name of an enum type.

To make the code valid, remove the invalid qualifier E::.



Note - Use of this option increases the possibility of typographical errors yielding incorrect programs that compile without error messages.




4.5 Using Anonymous struct Declarations

An anonymous struct declaration is a declaration that declares neither a tag for the struct, nor an object or typedef name. Anonymous structs are not allowed in C++.

The -features=extensions option allows the use of an anonymous struct declaration, but only as member of a union.

The following code is an example of an invalid anonymous struct declaration that will compile when you use the -features=extensions option.

union U {
  struct {
    int a;
    double b;
  };  // invalid: anonymous struct
  struct {
    char* c;
    unsigned d;
  };  // invalid: anonymous struct
};

The names of the struct members are visible without qualification by a struct member name. Given the definition of U in this code example, you can write:

U u;
u.a = 1;

Anonymous structs are subject to the same limitations as anonymous unions.

Note that you can make the code valid by giving a name to each struct, such as:

union U {
  struct {
    int a;
    double b;
  } A;
  struct {
    char* c;
    unsigned d;
  } B;
};
U u;
U.A.a = 1;


4.6 Passing the Address of an Anonymous Class Instance

You are not allowed to take the address of a temporary variable. For example, the following code is invalid because it takes the address of a variable created by a constructor call. However, the compiler accepts this invalid code when you use the -features=extensions option.

class C {
  public:
    C(int);
    ...
};
void f1(C*);
int main()
{
  f1( &C(2) ); // invalid
}

Note that you can make this code valid by using an explicit variable.

C c(2);
f1(&c);

The temporary object is destroyed when the function returns. Ensuring that the address of the temporary variable is not retained is the programmer's responsibility. In addition, the data that is stored in the temporary variable (for example, by f1) is lost when the temporary variable is destroyed.


4.7 Declaring a Static Namespace-Scope Function as a Class Friend

The following code is invalid.

class A {
  friend static void foo(<args>);
  ...
};

Because a class name has external linkage and all definitions must be identical, friend functions must also have external linkage. However, when you use the -features=extensions option, the compiler to accepts this code.

Presumably the programmer's intent with this invalid code was to provide a nonmember "helper" function in the implementation file for class A. You can get the same effect by making foo a static member function. You can make it private if you do not want clients to call the function.



Note - If you use this extension, your class can be "hijacked" by any client. Any client can include the class header, then define its own static function foo, which will automatically be a friend of the class. The effect will be as if you made all members of the class public.




4.8 Using the Predefined __func__ Symbol for Function Name

When you use -features=extensions, the compiler implicitly declares the identifier __func__ in each function as a static array of const char. If the program uses the identifier, the compiler also provides the following definition where function-name is the unadorned name of the function. Class membership, namespaces, and overloading are not reflected in the name.

static const char __func__[] = "function-name";

For example, consider the following code fragment.

#include <stdio.h>
void myfunc(void)
{
  printf("%s\n", __func__);
}

Each time the function is called, it will print the following to the standard output stream.

myfunc