The main function of the compiler is to translate source code to machine code but, during the development of a project, we inevitably make some mistake.
An important aspect of a good compiler is the capability of generating clear and precise error and warning messages. Clear error messages help to quickly identify mistakes in the code whereas warning messages are potential issues the compiler found in the code that might be worth investigating.
ARM Compiler 6 is based on the well-known Clang compiler which provides more precise and accurate warning/error messages compared to other tool-chains. Let's have a look at some examples:
Let’s try to write an example code:
#include <stdio.h> int main() { int a = 0, b = 0; if (a = b) { printf("Right\n"); } else { printf("Wrong\n"); } return 0; }
We made a mistake in the code by using ‘=’ instead of ‘==’. The code above is legitimate C language; it is the error in logic that will trip you up. Let’s see how different compilers help the developer identify the logic error:
ARM Compiler 5 "main.cpp", line 6: Warning: #1293-D: assignment in condition if (a = b) { ^
ARM Compiler 5
"main.cpp", line 6: Warning: #1293-D: assignment in condition
if (a = b) {
^
ARM Compiler 6 main.cpp:6:11: warning: using the result of an assignment as a condition without parentheses [-Wparentheses] if (a = b) { ~~^~~ main.cpp:6:11: note: place parentheses around the assignment to silence this warning if (a = b) { ^ ( ) main.cpp:6:11: note: use '==' to turn this assignment into an equality comparison if (a = b) { ^ ==
ARM Compiler 6
main.cpp:6:11: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
~~^~~
main.cpp:6:11: note: place parentheses around the assignment to silence this warning
( )
main.cpp:6:11: note: use '==' to turn this assignment into an equality comparison
==
GCC 4.9 main.cpp: In function ‘int main()’: main.cpp:6:14: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
GCC 4.9
main.cpp: In function ‘int main()’:
main.cpp:6:14: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
As you can see from the different outputs, ARM Compiler 6 not only indicates what it thinks is wrong in the code, but it also suggests two different ways to resolve the issue. The warning messages quote the entire line and highlight the specific part which requires attention from the user.
Templates are a great feature of C++ but they are sometimes a source of head-aches when troubleshooting problems. Let’s have a look at another example, this time involving C++ templates:
int sum_vector(const std::vector<int> &input) { std::vector<float>::const_iterator i = input.begin(); int sum = 0; for(; i != input.end(); ++i) { sum += *i; } return sum; }
The root of the error is that the template type used for the const_iterator is float whereas the vector requires int. How do different compilers identify this error?
ARM Compiler 5 "main.cpp", line 5: Error: #144: a value of type "const int *" cannot be used to initialize an entity of type "const float *" std::vector<float>::const_iterator i = input.begin(); ^
"main.cpp", line 5: Error: #144: a value of type "const int *" cannot be used to initialize an entity of type "const float *"
std::vector<float>::const_iterator i = input.begin();
ARM Compiler 6 main.cpp:5:40: error: cannot initialize a variable of type 'std::vector<float>::const_iterator' (aka 'const float *') with an rvalue of type 'const_iterator' (aka 'const int *') 'std::vector<float>::const_iterator i = input.begin(); ^ ~~~~~~~~~~~~~
main.cpp:5:40: error: cannot initialize a variable of type 'std::vector<float>::const_iterator' (aka 'const float *') with an rvalue of type 'const_iterator' (aka 'const int *')
'std::vector<float>::const_iterator i = input.begin();
^ ~~~~~~~~~~~~~
GCC 4.9 main.cpp: In function ‘int sum_vector(const std::vector<int>&)’: main.cpp:5:56: error: conversion from ‘std::vector<int>::const_iterator {aka __gnu_cxx::__normal_iterator<const int*, std::vector<int> >}’ to non-scalar type ‘std::vector<float>::const_iterator {aka __gnu_cxx::__normal_iterator<const float*, std::vector<float> >}’ requested main.cpp:7:26: error: no match for ‘operator!=’ in ‘i != (& input)->std::vector<_Tp, _Alloc>::end<int, std::allocator<int> >()’ main.cpp:7:26: note: candidates are: In file included from /usr/include/x86_64-linux-gnu/c++/4.7/./bits/c++allocator.h:34:0, from /usr/include/c++/4.7/bits/allocator.h:48, … (additional 98 lines following)
main.cpp: In function ‘int sum_vector(const std::vector<int>&)’:
main.cpp:5:56: error: conversion from ‘std::vector<int>::const_iterator {aka __gnu_cxx::__normal_iterator<const int*, std::vector<int> >}’ to non-scalar type ‘std::vector<float>::const_iterator {aka __gnu_cxx::__normal_iterator<const float*, std::vector<float> >}’ requested
main.cpp:7:26: error: no match for ‘operator!=’ in ‘i != (& input)->std::vector<_Tp, _Alloc>::end<int, std::allocator<int> >()’
main.cpp:7:26: note: candidates are:
In file included from /usr/include/x86_64-linux-gnu/c++/4.7/./bits/c++allocator.h:34:0,
from /usr/include/c++/4.7/bits/allocator.h:48,
…
(additional 98 lines following)
The error messages produced by ARM Compiler 5 and ARM Compiler 6 are self-explaining and give a clear suggestion to the user on how to fix the issue: the mismatching template types are clearly indicated in the error message and the caret points the user to the precise point within the code. GCC, on the other hand, generates about 100 lines of hard-to-understand error messages.
Another very useful feature of diagnostic messages in ARM Compiler 6 is the automatic macro expansion. Consider the following code:
#define LOG(PREFIX, MESSAGE) fprintf(stderr, "%s: %s", PREFIX, MESSAGE) #define LOG_WARNING(MESSAGE) LOG("Warning", MESSAGE) … LOG_WARNING(123); …
LOG_WARNING has been called with an integer as an argument even though, by expanding the two macros, you can see the fprintf function is expecting a string. When the macros are close together in the code it’s easy to spot these errors: what if they are defined in different part of the source code, or worse, in some external libraries ?
ARM Compiler 6 automatically expands each macro involved so that you can easily see what’s wrong in the call chain as shown below:
ARM Compiler 6 main.cpp:8:14: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat] LOG_WARNING(123); ~~~~~~~~~~~~^~~ main.cpp:5:45: note: expanded from macro 'LOG_WARNING' #define LOG_WARNING(MESSAGE) LOG("Warning", MESSAGE) ^ main.cpp:3:64: note: expanded from macro 'LOG' #define LOG(PREFIX, MESSAGE) fprintf(stderr, "%s: %s", PREFIX, MESSAGE) ^
main.cpp:8:14: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
LOG_WARNING(123);
~~~~~~~~~~~~^~~
main.cpp:5:45: note: expanded from macro 'LOG_WARNING'
#define LOG_WARNING(MESSAGE) LOG("Warning", MESSAGE)
main.cpp:3:64: note: expanded from macro 'LOG'
#define LOG(PREFIX, MESSAGE) fprintf(stderr, "%s: %s", PREFIX, MESSAGE)
In summary we have seen how ARM Compiler 6 is able to give precise and detailed warning and error messages, simplifying the important task of troubleshooting coding errors. The quality of the error and warning messages not only helps the developer spot potential bugs in the final product, but also to quickly understand and fix them by providing sensible and easy to decipher suggestions.
I hope that you found this blog post useful and you are looking forward to using ARM Compiler 6 ! If you still don’t have DS-5, download a free 30-day evaluation .
Feel free to post any questions or comments below.
Ciao,
Stefano