forked from OSchip/llvm-project
Update page on clang diagnostics to contrast to GCC 4.9 instead of 4.2. A lot
of the differences we identified here have been fixed by improvements in GCC. llvm-svn: 199970
This commit is contained in:
parent
61adb27de4
commit
0e50a883ff
|
@ -7,10 +7,14 @@
|
|||
<link type="text/css" rel="stylesheet" href="menu.css">
|
||||
<link type="text/css" rel="stylesheet" href="content.css">
|
||||
<style type="text/css">
|
||||
.warn { color:magenta; }
|
||||
.err { color:red; }
|
||||
.snip { color:darkgreen; }
|
||||
.point { color:blue; }
|
||||
.loc { font-weight: bold; }
|
||||
.err { color:red; font-weight: bold; }
|
||||
.warn { color:magenta; font-weight: bold; }
|
||||
.note { color:gray; font-weight: bold; }
|
||||
.msg { font-weight: bold; }
|
||||
.cmd { font-style: italic; }
|
||||
.snip { }
|
||||
.point { color:green; font-weight: bold; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -29,10 +33,7 @@ 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.
|
||||
<!--
|
||||
Other clients
|
||||
that embed Clang and extract equivalent information through internal APIs.-->
|
||||
Clang output to GCC 4.9's output in some cases.
|
||||
</p>
|
||||
|
||||
<h2>Column Numbers and Caret Diagnostics</h2>
|
||||
|
@ -41,25 +42,35 @@ that embed Clang and extract equivalent information through internal APIs.-->
|
|||
information. The clang command-line compiler driver uses this information
|
||||
to print "point diagnostics".
|
||||
(IDEs can use the information to display in-line error markup.)
|
||||
Precise error location in the source 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</p>
|
||||
This is nice because it makes it very easy to understand exactly
|
||||
what is wrong in a particular piece of code.</p>
|
||||
|
||||
<p>The point (the blue "^" character) exactly shows where the problem is, even
|
||||
<p>The point (the green "^" character) exactly shows where the problem is, even
|
||||
inside of a 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.)</p>
|
||||
|
||||
<pre>
|
||||
$ <b>gcc-4.2 -fsyntax-only -Wformat format-strings.c</b>
|
||||
format-strings.c:91: warning: too few arguments for format
|
||||
$ <b>clang -fsyntax-only format-strings.c</b>
|
||||
format-strings.c:91:13: <span class="warn">warning:</span> '.*' specified field precision is missing a matching 'int' argument
|
||||
<span class="snip"> printf("%.*d");</span>
|
||||
$ <span class="cmd">gcc-4.9 -fsyntax-only -Wformat format-strings.c</span>
|
||||
format-strings.c: In function 'void f()':
|
||||
format-strings.c:91:16: warning: field precision specifier '.*' expects a matching 'int' argument [-Wformat=]
|
||||
printf("%.*d");
|
||||
^
|
||||
format-strings.c:91:16: warning: format '%d' expects a matching 'int' argument [-Wformat=]
|
||||
$ <span class="cmd">clang -fsyntax-only format-strings.c</span>
|
||||
<span class="loc">format-strings.c:91:13:</span> <span class="warn">warning:</span> <span class="msg">'.*' specified field precision is missing a matching 'int' argument</span>
|
||||
<span class="snip" > printf("%.*d");</span>
|
||||
<span class="point"> ^</span>
|
||||
</pre>
|
||||
|
||||
<p>Note that modern versions of GCC have followed Clang's lead, and are
|
||||
now able to give a column for a diagnostic, and include a snippet of source
|
||||
text in the result. However, Clang's column number is much more accurate,
|
||||
pointing at the problematic format specifier, rather than the <tt>)</tt>
|
||||
character the parser had reached when the problem was detected.
|
||||
Also, Clang's diagnostic is colored by default, making it easier to
|
||||
distinguish from nearby text.</p>
|
||||
|
||||
<h2>Range Highlighting for Related Text</h2>
|
||||
|
||||
<p>Clang captures and accurately tracks range information for expressions,
|
||||
|
@ -74,11 +85,14 @@ Range information is very useful for
|
|||
cases involving precedence issues and many other cases.</p>
|
||||
|
||||
<pre>
|
||||
$ <b>gcc-4.2 -fsyntax-only t.c</b>
|
||||
t.c:7: error: invalid operands to binary + (have 'int' and 'struct A')
|
||||
$ <b>clang -fsyntax-only t.c</b>
|
||||
t.c:7:39: <span class="err">error:</span> invalid operands to binary expression ('int' and 'struct A')
|
||||
<span class="snip"> return y + func(y ? ((SomeA.X + 40) + SomeA) / 42 + SomeA.X : SomeA.X);</span>
|
||||
$ <span class="cmd">gcc-4.9 -fsyntax-only t.c</span>
|
||||
t.c: In function 'int f(int, int)':
|
||||
t.c:7:39: error: invalid operands to binary + (have 'int' and 'struct A')
|
||||
return y + func(y ? ((SomeA.X + 40) + SomeA) / 42 + SomeA.X : SomeA.X);
|
||||
^
|
||||
$ <span class="cmd">clang -fsyntax-only t.c</span>
|
||||
<span class="loc">t.c:7:39:</span> <span class="err">error:</span> <span class="msg">invalid operands to binary expression ('int' and 'struct A')</span>
|
||||
<span class="snip" > return y + func(y ? ((SomeA.X + 40) + SomeA) / 42 + SomeA.X : SomeA.X);</span>
|
||||
<span class="point"> ~~~~~~~~~~~~~~ ^ ~~~~~</span>
|
||||
</pre>
|
||||
|
||||
|
@ -90,62 +104,24 @@ 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
|
||||
point (e.g., that this is a "binary +").</p>
|
||||
|
||||
<p>Many other examples abound. In the following example, not only do we tell you that there is a problem with the *
|
||||
<p>Many other examples abound. In the following example, not only do we tell you
|
||||
that there is a problem with the <tt>*</tt>
|
||||
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.</p>
|
||||
|
||||
<pre>
|
||||
$ <b>gcc-4.2 -fsyntax-only t.c</b>
|
||||
t.c:5: error: invalid type argument of 'unary *'
|
||||
$ <b>clang -fsyntax-only t.c</b>
|
||||
t.c:5:11: <span class="err">error:</span> indirection requires pointer operand ('int' invalid)
|
||||
<span class="snip"> int y = *SomeA.X;</span>
|
||||
$ <span class="cmd">gcc-4.9 -fsyntax-only t.c</span>
|
||||
t.c:5:11: error: invalid type argument of unary '*' (have 'int')
|
||||
return *SomeA.X;
|
||||
^
|
||||
$ <span class="cmd">clang -fsyntax-only t.c</span>
|
||||
<span class="loc">t.c:5:11:</span> <span class="err">error:</span> <span class="msg">indirection requires pointer operand ('int' invalid)</span>
|
||||
<span class="snip" > int y = *SomeA.X;</span>
|
||||
<span class="point"> ^~~~~~~~</span>
|
||||
</pre>
|
||||
|
||||
<h2>No Pretty Printing of Expressions in Diagnostics</h2>
|
||||
|
||||
<p>Since Clang has range highlighting, it never needs to pretty print your code
|
||||
back out to you. GCC can produce inscrutible error messages in some cases when
|
||||
it tries to do this. In this example P and Q have type "int*":</p>
|
||||
|
||||
<pre>
|
||||
$ <b>gcc-4.2 -fsyntax-only t.c</b>
|
||||
#'exact_div_expr' not supported by pp_c_expression#'t.c:12: error: called object is not a function
|
||||
$ <b>clang -fsyntax-only t.c</b>
|
||||
t.c:12:8: <span class="err">error:</span> called object type 'int' is not a function or function pointer
|
||||
<span class="snip"> (P-Q)();</span>
|
||||
<span class="point"> ~~~~~^</span>
|
||||
</pre>
|
||||
|
||||
<p>This can be particularly bad in G++, which often emits errors
|
||||
containing lowered vtable references. For example:</p>
|
||||
|
||||
<pre>
|
||||
$ <b>cat t.cc</b>
|
||||
struct a {
|
||||
virtual int bar();
|
||||
};
|
||||
|
||||
struct foo : public virtual a {
|
||||
};
|
||||
|
||||
void test(foo *P) {
|
||||
return P->bar() + *P;
|
||||
}
|
||||
$ <b>gcc-4.2 t.cc</b>
|
||||
t.cc: In function 'void test(foo*)':
|
||||
t.cc:9: error: no match for 'operator+' in '(((a*)P) + (*(long int*)(P->foo::<anonymous>.a::_vptr$a + -0x00000000000000020)))->a::bar() + * P'
|
||||
t.cc:9: error: return-statement with a value, in function returning 'void'
|
||||
$ <b>clang t.cc</b>
|
||||
t.cc:9:18: <span class="err">error:</span> invalid operands to binary expression ('int' and 'foo')
|
||||
<span class="snip"> return P->bar() + *P;</span>
|
||||
<span class="point"> ~~~~~~~~ ^ ~~</span>
|
||||
</pre>
|
||||
|
||||
|
||||
<h2>Typedef Preservation and Selective Unwrapping</h2>
|
||||
|
||||
<p>Many programmers use high-level user defined types, typedefs, and other
|
||||
|
@ -156,15 +132,11 @@ trivial types and it is important to strip off the typedef to understand what
|
|||
is going on. Clang aims to handle both cases well.<p>
|
||||
|
||||
<p>The following example shows where it is important to preserve
|
||||
a typedef in C. 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.</p>
|
||||
a typedef in C.</p>
|
||||
|
||||
<pre>
|
||||
$ <b>gcc-4.2 -fsyntax-only t.c</b>
|
||||
t.c:15: error: invalid operands to binary / (have 'float __vector__' and 'const int *')
|
||||
$ <b>clang -fsyntax-only t.c</b>
|
||||
t.c:15:11: <span class="err">error:</span> can't convert between vector values of different size ('__m128' and 'int const *')
|
||||
$ <span class="cmd">clang -fsyntax-only t.c</span>
|
||||
<span class="loc">t.c:15:11:</span> <span class="err">error:</span> <span class="msg">can't convert between vector values of different size ('__m128' and 'int const *')</span>
|
||||
<span class="snip"> myvec[1]/P;</span>
|
||||
<span class="point"> ~~~~~~~~^~</span>
|
||||
</pre>
|
||||
|
@ -174,10 +146,8 @@ underlying details of a typedef. If the user was somehow confused about how the
|
|||
system "pid_t" typedef is defined, Clang helpfully displays it with "aka".</p>
|
||||
|
||||
<pre>
|
||||
$ <b>gcc-4.2 -fsyntax-only t.c</b>
|
||||
t.c:13: error: request for member 'x' in something not a structure or union
|
||||
$ <b>clang -fsyntax-only t.c</b>
|
||||
t.c:13:9: <span class="err">error:</span> member reference base type 'pid_t' (aka 'int') is not a structure or union
|
||||
$ <span class="cmd">clang -fsyntax-only t.c</span>
|
||||
<span class="loc">t.c:13:9:</span> <span class="err">error:</span> <span class="msg">member reference base type 'pid_t' (aka 'int') is not a structure or union</span>
|
||||
<span class="snip"> myvar = myvar.x;</span>
|
||||
<span class="point"> ~~~~~ ^</span>
|
||||
</pre>
|
||||
|
@ -202,13 +172,11 @@ void addHTTPService(servers::Server const &server, ::services::WebService co
|
|||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>and then compile it, we see that Clang is both providing more accurate information and is retaining the types as written by the user (e.g., "servers::Server", "::services::WebService"):
|
||||
<p>and then compile it, we see that Clang is both providing accurate information and is retaining the types as written by the user (e.g., "servers::Server", "::services::WebService"):
|
||||
|
||||
<pre>
|
||||
$ <b>g++-4.2 -fsyntax-only t.cpp</b>
|
||||
t.cpp:9: error: no match for 'operator+=' in 'server += http'
|
||||
$ <b>clang -fsyntax-only t.cpp</b>
|
||||
t.cpp:9:10: <span class="err">error:</span> invalid operands to binary expression ('servers::Server const' and '::services::WebService const *')
|
||||
$ <span class="cmd">clang -fsyntax-only t.cpp</span>
|
||||
<span class="loc">t.cpp:9:10:</span> <span class="err">error:</span> <span class="msg">invalid operands to binary expression ('servers::Server const' and '::services::WebService const *')</span>
|
||||
<span class="snip">server += http;</span>
|
||||
<span class="point">~~~~~~ ^ ~~~~</span>
|
||||
</pre>
|
||||
|
@ -216,10 +184,8 @@ void addHTTPService(servers::Server const &server, ::services::WebService co
|
|||
<p>Naturally, type preservation extends to uses of templates, and Clang retains information about how a particular template specialization (like <code>std::vector<Real></code>) was spelled within the source code. For example:</p>
|
||||
|
||||
<pre>
|
||||
$ <b>g++-4.2 -fsyntax-only t.cpp</b>
|
||||
t.cpp:12: error: no match for 'operator=' in 'str = vec'
|
||||
$ <b>clang -fsyntax-only t.cpp</b>
|
||||
t.cpp:12:7: <span class="err">error:</span> incompatible type assigning 'vector<Real>', expected 'std::string' (aka 'class std::basic_string<char>')
|
||||
$ <span class="cmd">clang -fsyntax-only t.cpp</span>
|
||||
<span class="loc">t.cpp:12:7:</span> <span class="err">error:</span> <span class="msg">incompatible type assigning 'vector<Real>', expected 'std::string' (aka 'class std::basic_string<char>')</span>
|
||||
<span class="snip">str = vec</span>;
|
||||
<span class="point">^ ~~~</span>
|
||||
</pre>
|
||||
|
@ -237,14 +203,14 @@ code should be removed, then replaced with the code below the
|
|||
point line (".x =" or ".y =", respectively).</p>
|
||||
|
||||
<pre>
|
||||
$ <b>clang t.c</b>
|
||||
t.c:5:28: <span class="warn">warning:</span> use of GNU old-style field designator extension
|
||||
$ <span class="cmd">clang t.c</span>
|
||||
<span class="loc">t.c:5:28:</span> <span class="warn">warning:</span> <span class="msg">use of GNU old-style field designator extension</span>
|
||||
<span class="snip">struct point origin = { x: 0.0, y: 0.0 };</span>
|
||||
<span class="err">~~</span> <span class="point">^</span>
|
||||
<span class="err">~~</span> <span class="msg"><span class="point">^</span></span>
|
||||
<span class="snip">.x = </span>
|
||||
t.c:5:36: <span class="warn">warning:</span> use of GNU old-style field designator extension
|
||||
<span class="loc">t.c:5:36:</span> <span class="warn">warning:</span> <span class="msg">use of GNU old-style field designator extension</span>
|
||||
<span class="snip">struct point origin = { x: 0.0, y: 0.0 };</span>
|
||||
<span class="err">~~</span> <span class="point">^</span>
|
||||
<span class="err">~~</span> <span class="msg"><span class="point">^</span></span>
|
||||
<span class="snip">.y = </span>
|
||||
</pre>
|
||||
|
||||
|
@ -256,8 +222,8 @@ Clang provides the fix--add <code>template<></code>--as part of the
|
|||
diagnostic.<p>
|
||||
|
||||
<pre>
|
||||
$ <b>clang t.cpp</b>
|
||||
t.cpp:9:3: <span class="err">error:</span> template specialization requires 'template<>'
|
||||
$ <span class="cmd">clang t.cpp</span>
|
||||
<span class="loc">t.cpp:9:3:</span> <span class="err">error:</span> <span class="msg">template specialization requires 'template<>'</span>
|
||||
struct iterator_traits<file_iterator> {
|
||||
<span class="point">^</span>
|
||||
<span class="snip">template<> </span>
|
||||
|
@ -273,15 +239,15 @@ printed as an indented text tree.</p>
|
|||
|
||||
Default: template diff with type elision
|
||||
<pre>
|
||||
t.cc:4:5: <span class="note">note:</span> candidate function not viable: no known conversion from 'vector<map<[...], <span class="template-highlight">float</span>>>' to 'vector<map<[...], <span class="template-highlight">double</span>>>' for 1st argument;
|
||||
<span class="loc">t.cc:4:5:</span> <span class="note">note:</span> candidate function not viable: no known conversion from 'vector<map<[...], <span class="template-highlight">float</span>>>' to 'vector<map<[...], <span class="template-highlight">double</span>>>' for 1st argument;
|
||||
</pre>
|
||||
-fno-elide-type: template diff without elision
|
||||
<pre>
|
||||
t.cc:4:5: <span class="note">note:</span> candidate function not viable: no known conversion from 'vector<map<int, <span class="template-highlight">float</span>>>' to 'vector<map<int, <span class="template-highlight">double</span>>>' for 1st argument;
|
||||
<span class="loc">t.cc:4:5:</span> <span class="note">note:</span> candidate function not viable: no known conversion from 'vector<map<int, <span class="template-highlight">float</span>>>' to 'vector<map<int, <span class="template-highlight">double</span>>>' for 1st argument;
|
||||
</pre>
|
||||
-fdiagnostics-show-template-tree: template tree printing with elision
|
||||
<pre>
|
||||
t.cc:4:5: <span class="note">note:</span> candidate function not viable: no known conversion for 1st argument;
|
||||
<span class="loc">t.cc:4:5:</span> <span class="note">note:</span> candidate function not viable: no known conversion for 1st argument;
|
||||
vector<
|
||||
map<
|
||||
[...],
|
||||
|
@ -289,7 +255,7 @@ t.cc:4:5: <span class="note">note:</span> candidate function not viable: no know
|
|||
</pre>
|
||||
-fdiagnostics-show-template-tree -fno-elide-type: template tree printing with no elision
|
||||
<pre>
|
||||
t.cc:4:5: <span class="note">note:M</span> candidate function not viable: no known conversion for 1st argument;
|
||||
<span class="loc">t.cc:4:5:</span> <span class="note">note:</span> candidate function not viable: no known conversion for 1st argument;
|
||||
vector<
|
||||
map<
|
||||
int,
|
||||
|
@ -306,14 +272,11 @@ 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.</p>
|
||||
|
||||
<pre>
|
||||
$ <b>gcc-4.2 -fsyntax-only t.c</b>
|
||||
t.c: In function 'test':
|
||||
t.c:80: error: invalid operands to binary < (have 'struct mystruct' and 'float')
|
||||
$ <b>clang -fsyntax-only t.c</b>
|
||||
t.c:80:3: <span class="err">error:</span> invalid operands to binary expression ('typeof(P)' (aka 'struct mystruct') and 'typeof(F)' (aka 'float'))
|
||||
$ <span class="cmd">clang -fsyntax-only t.c</span>
|
||||
<span class="loc">t.c:80:3:</span> <span class="err">error:</span> <span class="msg">invalid operands to binary expression ('typeof(P)' (aka 'struct mystruct') and 'typeof(F)' (aka 'float'))</span>
|
||||
<span class="snip"> X = MYMAX(P, F);</span>
|
||||
<span class="point"> ^~~~~~~~~~~</span>
|
||||
t.c:76:94: note: expanded from:
|
||||
<span class="loc">t.c:76:94:</span> <span class="note">note:</span> expanded from:
|
||||
<span class="snip">#define MYMAX(A,B) __extension__ ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __b : __a; })</span>
|
||||
<span class="point"> ~~~ ^ ~~~</span>
|
||||
</pre>
|
||||
|
@ -322,14 +285,14 @@ and also shows how some of the other pieces work in a bigger example.</p>
|
|||
implements the "wwopen" class of APIs):</p>
|
||||
|
||||
<pre>
|
||||
$ <b>clang -fsyntax-only t.c</b>
|
||||
t.c:22:2: <span class="warn">warning:</span> type specifier missing, defaults to 'int'
|
||||
$ <span class="cmd">clang -fsyntax-only t.c</span>
|
||||
<span class="loc">t.c:22:2:</span> <span class="warn">warning:</span> <span class="msg">type specifier missing, defaults to 'int'</span>
|
||||
<span class="snip"> ILPAD();</span>
|
||||
<span class="point"> ^</span>
|
||||
t.c:17:17: note: expanded from:
|
||||
<span class="loc">t.c:17:17:</span> <span class="note">note:</span> expanded from:
|
||||
<span class="snip">#define ILPAD() PAD((NROW - tt.tt_row) * 10) /* 1 ms per char */</span>
|
||||
<span class="point"> ^</span>
|
||||
t.c:14:2: note: expanded from:
|
||||
<span class="loc">t.c:14:2:</span> <span class="note">note:</span> expanded from:
|
||||
<span class="snip"> register i; \</span>
|
||||
<span class="point"> ^</span>
|
||||
</pre>
|
||||
|
@ -342,63 +305,65 @@ macros that in simple ones.</p>
|
|||
<p>Finally, we have put a lot of work polishing the little things, because
|
||||
little things add up over time and contribute to a great user experience.</p>
|
||||
|
||||
<p>The following example shows a trivial little tweak, where we tell you to put the semicolon at
|
||||
the end of the line that is missing it (line 4) instead of at the beginning of
|
||||
the following line (line 5). This is particularly important with fixit hints
|
||||
and point diagnostics, because otherwise you don't get the important context.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
$ <b>gcc-4.2 t.c</b>
|
||||
t.c: In function 'foo':
|
||||
t.c:5: error: expected ';' before '}' token
|
||||
$ <b>clang t.c</b>
|
||||
t.c:4:8: <span class="err">error:</span> expected ';' after expression
|
||||
<span class="snip"> bar()</span>
|
||||
<span class="point"> ^</span>
|
||||
<span class="point"> ;</span>
|
||||
</pre>
|
||||
|
||||
<p>The following example shows much better error recovery than GCC. The message coming out
|
||||
of GCC is completely useless for diagnosing the problem. Clang tries much harder
|
||||
and produces a much more useful diagnosis of the problem.</p>
|
||||
|
||||
<pre>
|
||||
$ <b>gcc-4.2 t.c</b>
|
||||
t.c:3: error: expected '=', ',', ';', 'asm' or '__attribute__' before '*' token
|
||||
$ <b>clang t.c</b>
|
||||
t.c:3:1: <span class="err">error:</span> unknown type name 'foo_t'
|
||||
<span class="snip">foo_t *P = 0;</span>
|
||||
<span class="point">^</span>
|
||||
</pre>
|
||||
|
||||
<p>The following example shows that we recover from the simple case of
|
||||
forgetting a ; after a struct definition much better than GCC.</p>
|
||||
|
||||
<pre>
|
||||
$ <b>cat t.cc</b>
|
||||
$ <span class="cmd">cat t.cc</span>
|
||||
template<class T>
|
||||
class a {}
|
||||
class temp {};
|
||||
a<temp> b;
|
||||
struct b {
|
||||
}
|
||||
$ <b>gcc-4.2 t.cc</b>
|
||||
t.cc:3: error: multiple types in one declaration
|
||||
t.cc:4: error: non-template type 'a' used as a template
|
||||
t.cc:4: error: invalid type in declaration before ';' token
|
||||
t.cc:6: error: expected unqualified-id at end of input
|
||||
$ <b>clang t.cc</b>
|
||||
t.cc:2:11: <span class="err">error:</span> expected ';' after class
|
||||
<span class="snip">class a {}</span>
|
||||
<span class="point"> ^</span>
|
||||
<span class="point"> ;</span>
|
||||
t.cc:6:2: <span class="err">error:</span> expected ';' after struct
|
||||
<span class="snip">}</span>
|
||||
<span class="point"> ^</span>
|
||||
<span class="point"> ;</span>
|
||||
class a {};
|
||||
struct b {}
|
||||
a<int> c;
|
||||
$ <span class="cmd">gcc-4.9 t.cc</span>
|
||||
t.cc:4:8: error: invalid declarator before 'c'
|
||||
a<int> c;
|
||||
^
|
||||
$ <span class="cmd">clang t.cc</span>
|
||||
<span class="loc">t.cc:3:12:</span> <span class="err">error:</span> <span class="msg">expected ';' after struct</span>
|
||||
<span class="snip" >struct b {}</span>
|
||||
<span class="point"> ^</span>
|
||||
<span class="point"> ;</span>
|
||||
</pre>
|
||||
|
||||
<p>The following example shows that we diagnose and recover from a missing
|
||||
<tt>typename</tt> keyword well, even in complex circumstances where GCC
|
||||
cannot cope.</p>
|
||||
|
||||
<pre>
|
||||
$ <span class="cmd">cat t.cc</span>
|
||||
template<class T> void f(T::type) { }
|
||||
struct A { };
|
||||
void g()
|
||||
{
|
||||
A a;
|
||||
f<A>(a);
|
||||
}
|
||||
$ <span class="cmd">gcc-4.9 t.cc</span>
|
||||
t.cc:1:33: error: variable or field 'f' declared void
|
||||
template<class T> void f(T::type) { }
|
||||
^
|
||||
t.cc: In function 'void g()':
|
||||
t.cc:6:5: error: 'f' was not declared in this scope
|
||||
f<A>(a);
|
||||
^
|
||||
t.cc:6:8: error: expected primary-expression before '>' token
|
||||
f<A>(a);
|
||||
^
|
||||
$ <span class="cmd">clang t.cc</span>
|
||||
<span class="loc">t.cc:1:26:</span> <span class="error">error:</span> <span class="msg">missing 'typename' prior to dependent type name 'T::type'</span>
|
||||
<span class="snip" >template<class T> void f(T::type) { }</span>
|
||||
<span class="point"> ^~~~~~~</span>
|
||||
<span class="point"> typename </span>
|
||||
<span class="loc">t.cc:6:5:</span> <span class="error">error:</span> <span class="msg">no matching function for call to 'f'</span>
|
||||
<span class="snip" > f<A>(a);</span>
|
||||
<span class="point"> ^~~~</span>
|
||||
<span class="loc">t.cc:1:24:</span> <span class="note">note:</span> <span class="msg">candidate template ignored: substitution failure [with T = A]: no type named 'type' in 'A'</span>
|
||||
<span class="snip" >template<class T> void f(T::type) { }</span>
|
||||
<span class="point"> ^ ~~~~</span>
|
||||
</pre>
|
||||
|
||||
|
||||
|
||||
<p>While each of these details is minor, we feel that they all add up to provide
|
||||
a much more polished experience.</p>
|
||||
|
||||
|
|
Loading…
Reference in New Issue