ARM Technical Support Knowledge Articles

Support for non-ISO C++ Syntax in RVCT

Applies to: RealView Development Suite (RVDS)

Answer

Non-standard C++ syntax is regularly encountered when porting C++ code. Non-conforming code may be allowed by less-strictly conforming compilers, but is less portable. The best approach is to correct the code so that it conforms to the ISO standard. If you cannot correct the code, then the RVCT compilers have some options to allow some non-conformities:

--friend_injection
--no_parse_templates
--no_dep_name
--using_std
--diag_suppress nnn, --diag_warning nnn

Examples of some common non-conformities are given below, together with the corresponding compiler switch to allow it to compile with RVCT, and the corrected code.

  1. --friend_injection

    This allows the following (old style) code:

    Example of non-conforming use:

    //-- nonconform1.c --
    struct X {
    friend int f(); // this used to declare f in the surrounding
    // scope but not anymore
    };
    int g() {
    return f(); // without --friend_injection
    // Error: #20: identifier "f" is undefined
    }

    Example of conforming use:

    //-- conform1.c --
    int f(); // added declaration
    struct X {
    friend int f();
    };
    int g() {
    return f(); // now OK
    }
  2. --no_parse_templates

    Without --no_parse_templates, templates are analyzed when they are defined.

    Example of non-conforming use:

    //-- nonconform2.c --
    #include <stddef.h> // for size_t
    /* gives an error because S is undefined, unless compiled
    with --no_parse_templates
    */
    template <class T> size_t f(T t) { return sizeof(S) * t; }
    struct S { int s[10]; };
    size_t g() { return f(2); }

    Example of conforming use:

    //-- conform2.c --
    #include <stddef.h> // for size_t
    struct S { int s[10]; };
    template <class T> size_t f(T t) { return sizeof(S) * t; }
    size_t g() { return f(2); }
  3. --no_dep_name

    This option is a subset of '--no_parse_templates'. When conforming to the C++ standard, names that are not "type-dependant" are looked up at the point the template is defined - and not in any type-dependant base classes.

    Example of non-conforming use:

    //-- nonconform3.h --
    /* gives an error because g is undefined, unless compiled
    with --no_dep_name
    */
    template<class T> struct X;
    template<class T> struct Y : X<T> { static int f(T t) { return g(0) * t; } };
    //-- nonconform3-1.c --
    #include "nonconform3.h"
    template<class T> struct X { };
    int g(int i) { return i; }
    int h1() {return Y<int>::f(2);} // f(2) calls g(int) -> returns 0
    //-- nonconform3-2.c --
    #include "nonconform3.h"
    template<class T> struct X { };
    int g(short i) { return 1/i; }
    int h2() {return Y<int>::f(2);} // f(2) calls g(short) -> divides by 0!

    The reason the C++ standard disallows this is that having the meaning of g change in this way complicates writing robust templates. More discussion of this can be found in Stroustrup, "The C++ Programming Language, Third Edition" in section C.13.8.

    Example of conforming use:

    //-- conform3.h --
    /* The use of 'g' in the template function Y<>::f(T t) gets bound to g(void*)
    and later (overloaded) versions will not be considered
    */
    int g(void *) { return 3; }
    template<class T> struct X;
    template<class T> struct Y : X<T> { static int f(T t) { return g(0) * t; } };
    //-- conform3-1.c --
    #include "conform3.h"
    int g(int i) { return i; } // this g is not used by f
    template<class T> struct X { int g(int) { return 10; } }; /* this g is not used
    by Y<>::f */
    int h1() {return Y<int>::f(2);} // f(2) -> returns 6
    //-- conform3-2.c --
    #include "conform3.h"
    int g(short i) { return 1/i; } // this g is not used by f
    template<class T> struct X { int g(int) { return 100; } }; /* this g is not used
    by Y<>::f */
    int h2() {return Y<int>::f(2);} // f(2) -> returns 6

    Example of non-conforming use:

    //-- nonconform3-3.c --
    template<class T> struct ATemplate : public T {
    void Callfoo() {
    foo(); // not type-dependant, so will result in error
    // or use --no_dep_name
    }
    };

    Example of conforming use:

    //-- conform3-3.c --
    template<class T> struct ATemplate : public T {
    void Callfoo() {
    this->foo(); // make it (explicitly) type-dependant, now it is OK
    }
    };
  4. --using_std

    The C++ standard has defined that most of the C++ Language library is defined in the namespace 'std '. This means that references to objects and functions in that namespace need to use a correctly qualified name. Note this includes the C-library headers when they are included in the new form, for example: <cstddef>.

    Example of non-conforming use:

    //-- nonconform4.c --
    #include <cstddef> // new C++ form, though "stddef.h" is also allowed
    int f(size_t t);   // without --using_std, this will give an error
    // #20: identifier "size_t" is undefined
    #include <vector>  // there is no "vector.h"
    
    int g(vector<int> vi); // without --using_std, this will give an error
    

    There are four conforming ways to fix this:

    a. Use all names from the libraries correctly qualified. Disadvantage is that it can be a lot of work

    //-- conform4-1.c --
    #include <cstddef>
    int f(std::size_t t);
    #include <vector>
    int g(std::vector<int> vi);

    b. Import the names that are needed into the current namespace.

    //-- conform4-2.c --
    #include <cstddef>
    using std::size_t; // import the name size_t into the global namespace
    int f(size_t t);
    #include <vector>
    using std::vector; // import the name vector into the global namespace
    int g(vector<int> vi);

    c. Import all names from the namespace 'std' into the current namespace.
    Disadvantage is that the library names might clash with the user names in the current namespace.

    //-- conform4-3.c --
    #include <cstddef>
    using namespace std;
    int f(size_t t);
    #include <vector>
    // repeating using namespace std; is not needed
    int g(vector<int> vi);

    This is effectively what the option '--using_std' does.

    d. In case of the C-Library headers, use the old '.h' form of the include headers

    //-- conform4-4.c --
    #include <stddef.h> // both size_t and std::size_t are available
    int f(size_t t);
    int f(std::size_t t);
    // there is no "vector.h"
    
  5. --diag_suppress nnn, --diag_warning nnn

    Any error number that is postfixed with a '-D' can be configured to be either a warning or suppressed.

    Example of non-conforming use:

    struct X {
    private:
    int i;
    };
    struct Y : X {
    int g() { return i; } // i member of struct X
    // gives the error #265-D: member "X::i" is inaccessible
    };

    one could compile this example by using
    --diag_warning 265
    which turns the error into a warning. In general it is better to change the code, but there might be some reason why the code can not easily be modified.

Article last edited on: 2009-07-02 16:57:58

Rate this article

[Bad]
|
|
[Good]
Disagree? Move your mouse over the bar and click

Did you find this article helpful? Yes No

How can we improve this article?

Link to this article
Copyright © 2011 ARM Limited. All rights reserved. External (Open), Non-Confidential