From: Chris Lattner Date: Thu, 19 Mar 2009 06:52:51 +0000 (+0000) Subject: update our bragging about diagnostics. :) X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=13cc23508fe6fe46250dcf9401106cbb9d9d1e3d;p=clang update our bragging about diagnostics. :) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67289 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/www/feature-diagnostics1.png b/www/feature-diagnostics1.png deleted file mode 100644 index 00b0a0d719..0000000000 Binary files a/www/feature-diagnostics1.png and /dev/null differ diff --git a/www/features.html b/www/features.html index 7a491406c1..21f6ebcc8d 100644 --- a/www/features.html +++ b/www/features.html @@ -133,33 +133,188 @@ to tap the full potential of the clang design.

Expressive Diagnostics

-

Clang is designed to efficiently capture range information for expressions -and statements, which allows it to emit very useful and detailed diagnostic -information (e.g. warnings and errors) when a problem is detected.

- -

For example, this slide compares the diagnostics emitted by clang (top) to -the diagnostics emitted by GCC (middle) for a simple example:

- - - -

As you can see, clang goes beyond tracking just column number information: it -is able to highlight the subexpressions involved in a problem, making it much -easier to understand the source of the problem in many cases. For example, in -the first problem, it tells you why the operand is invalid (it -requires a pointer) and what type it really is.

- -

In the second error, you can see how clang uses column number information to -identify exactly which "+" out of the four on that line is causing the problem. -Further, it highlights the subexpressions involved, which can be very useful -when a complex subexpression that relies on tricky precedence rules.

- -

The example doesn't show it, but clang works very hard to retain typedef -information, ensuring that diagnostics print the user types, not the fully -expanded (and often huge) types. This is clearly important for C++ code (tell -me about "std::string", not about "std::basic_string<char, -std::char_traits<char>, std::allocator<char> >"!), but it is -also very useful in C code in some cases as well (e.g. "__m128" vs -"float __attribute__((__vector_size__(16)))").

+

In addition to being fast and functional, we aim to make Clang extremely user +friendly. As far as a command-line compiler goes, this basically boils down to +making the diagnostics (error and warning messages) generated by the compiler +be as useful as possible. There are several ways that we do this. This section +talks about the experience provided by the command line compiler, contrasting +Clang output to GCC 4.2's output in several examples. + +

+ +

Column Numbers and Caret Diagnostics

+ +

First, all diagnostics produced by clang include full column number +information, and use this to print "caret diagnostics". This is a feature +provided by many commercial compilers, but is generally missing from open source +compilers. This is nice because it makes it very easy to understand exactly +what is wrong in a particular piece of code, an example is:

+ +
+  $ gcc-4.2 -fsyntax-only -Wformat format-strings.c
+  format-strings.c:91: warning: too few arguments for format
+  $ clang -fsyntax-only format-strings.c
+  format-strings.c:91:13: warning: '.*' specified field precision is missing a matching 'int' argument
+    printf("%.*d");
+              ^
+
+ +

The caret (the blue "^" character) exactly shows where the problem is, even +inside of the string. This makes it really easy to jump to the problem and +helps when multiple instances of the same character occur on a line. We'll +revisit this more in following examples.

+ +

Range Highlighting for Related Text

+ +

Clang captures and accurately tracks range information for expressions, +statements, and other constructs in your program and uses this to make +diagnostics highlight related information. For example, here's a somewhat +nonsensical example to illustrate this:

+ +
+  $ gcc-4.2 -fsyntax-only t.c
+  t.c:7: error: invalid operands to binary + (have 'int' and 'struct A')
+  $ clang -fsyntax-only t.c
+  t.c:7:39: error: invalid operands to binary expression ('int' and 'struct A')
+    return y + func(y ? ((SomeA.X + 40) + SomeA) / 42 + SomeA.X : SomeA.X);
+                         ~~~~~~~~~~~~~~ ^ ~~~~~
+
+ +

Here you can see that you don't even need to see the original source code to +understand what is wrong based on the Clang error: Because clang prints a +caret, you know exactly which plus it is complaining about. The range +information highlights the left and right side of the plus which makes it +immediately obvious what the compiler is talking about, which is very useful for +cases involving precedence issues and many other cases.

+ +

Precision in Wording

+ +

A detail is that we have tried really hard to make the diagnostics that come +out of clang contain exactly the pertinent information about what is wrong and +why. In the example above, we tell you what the inferred types are for +the left and right hand sides, and we don't repeat what is obvious from the +caret (that this is a "binary +"). Many other examples abound, here is a simple +one:

+ +
+  $ gcc-4.2 -fsyntax-only t.c
+  t.c:5: error: invalid type argument of 'unary *'
+  $ clang -fsyntax-only t.c
+  t.c:5:11: error: indirection requires pointer operand ('int' invalid)
+    int y = *SomeA.X;
+            ^~~~~~~~
+
+ +

In this example, not only do we tell you that there is a problem with the * +and point to it, we say exactly why and tell you what the type is (in case it is +a complicated subexpression, such as a call to an overloaded function). This +sort of attention to detail makes it much easier to understand and fix problems +quickly.

+ +

No Pretty Printing of Expressions in Diagnostics

+ +

Since Clang has range highlighting, it never needs to pretty print your code +back out to you. This is particularly bad in G++ (which often emits errors +containing lowered vtable references), but even GCC can produce +inscrutible error messages in some cases when it tries to do this. In this +example P and Q have type "int*":

+ +
+  $ gcc-4.2 -fsyntax-only t.c
+  #'exact_div_expr' not supported by pp_c_expression#'t.c:12: error: called object  is not a function
+  $ clang -fsyntax-only t.c
+  t.c:12:8: error: called object type 'int' is not a function or function pointer
+    (P-Q)();
+    ~~~~~^
+
+ + +

Typedef Preservation and Selective Unwrapping

+ +

Many programmers use high-level user defined types, typedefs, and other +syntactic sugar to refer to types in their program. This is useful because they +can abbreviate otherwise very long types and it is useful to preserve the +typename in diagnostics. However, sometimes very simple typedefs can wrap +trivial types and it is important to strip off the typedef to understand what +is going on. Clang aims to handle both cases well.

+ +

For example, here is an example that shows where it is important to preserve +a typedef in C:

+ +
+  $ gcc-4.2 -fsyntax-only t.c
+  t.c:15: error: invalid operands to binary / (have 'float __vector__' and 'const int *')
+  $ clang -fsyntax-only t.c
+  t.c:15:11: error: can't convert between vector values of different size ('__m128' and 'int const *')
+    myvec[1]/P;
+    ~~~~~~~~^~
+
+ +

Here the type printed by GCC isn't even valid, but if the error were about a +very long and complicated type (as often happens in C++) the error message would +be ugly just because it was long and hard to read. Here's an example where it +is useful for the compiler to expose underlying details of a typedef:

+ +
+  $ gcc-4.2 -fsyntax-only t.c
+  t.c:13: error: request for member 'x' in something not a structure or union
+  $ clang -fsyntax-only t.c
+  t.c:13:9: error: member reference base type 'pid_t' (aka 'int') is not a structure or union
+    myvar = myvar.x;
+            ~~~~~ ^
+
+ +

If the user was somehow confused about how the system "pid_t" typedef is +defined, Clang helpfully displays it with "aka".

+ +

Automatic Macro Expansion

+ +

Many errors happen in macros that are sometimes deeply nested. With +traditional compilers, you need to dig deep into the definition of the macro to +understand how you got into trouble. Here's a simple example that shows how +Clang helps you out:

+ +
+  $ gcc-4.2 -fsyntax-only t.c
+  t.c: In function 'test':
+  t.c:80: error: invalid operands to binary < (have 'struct mystruct' and 'float')
+  $ clang -fsyntax-only t.c
+  t.c:80:3: error: invalid operands to binary expression ('typeof(P)' (aka 'struct mystruct') and 'typeof(F)' (aka 'float'))
+    X = MYMAX(P, F);
+        ^~~~~~~~~~~
+  t.c:76:94: note: instantiated from:
+  #define MYMAX(A,B)    __extension__ ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __b : __a; })
+                                                                                           ~~~ ^ ~~~
+
+ +

This shows how clang automatically prints instantiation information and +nested range information for diagnostics as they are instantiated through macros +and also shows how some of the other pieces work in a bigger example. Here's +another real world warning that occurs in the "window" Unix package (which +implements the "wwopen" class of APIs):

+ +
+  $ clang -fsyntax-only t.c
+  t.c:22:2: warning: type specifier missing, defaults to 'int'
+          ILPAD();
+          ^
+  t.c:17:17: note: instantiated from:
+  #define ILPAD() PAD((NROW - tt.tt_row) * 10)    /* 1 ms per char */
+                  ^
+  t.c:14:2: note: instantiated from:
+          register i; \
+          ^
+
+ +

In practice, we've found that this is actually more useful in multiply nested +macros that in simple ones.

+ + +

C++ Fun Examples

+ +

...

GCC Compatibility