1*67e74705SXin Li<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 2*67e74705SXin Li "http://www.w3.org/TR/html4/strict.dtd"> 3*67e74705SXin Li<html> 4*67e74705SXin Li<head> 5*67e74705SXin Li <meta http-equiv="content-type" content="text/html; charset=iso-8859-1"> 6*67e74705SXin Li <title>Clang - Expressive Diagnostics</title> 7*67e74705SXin Li <link type="text/css" rel="stylesheet" href="menu.css"> 8*67e74705SXin Li <link type="text/css" rel="stylesheet" href="content.css"> 9*67e74705SXin Li <style type="text/css"> 10*67e74705SXin Li .loc { font-weight: bold; } 11*67e74705SXin Li .err { color:red; font-weight: bold; } 12*67e74705SXin Li .warn { color:magenta; font-weight: bold; } 13*67e74705SXin Li .note { color:gray; font-weight: bold; } 14*67e74705SXin Li .msg { font-weight: bold; } 15*67e74705SXin Li .cmd { font-style: italic; } 16*67e74705SXin Li .snip { } 17*67e74705SXin Li .point { color:green; font-weight: bold; } 18*67e74705SXin Li </style> 19*67e74705SXin Li</head> 20*67e74705SXin Li<body> 21*67e74705SXin Li 22*67e74705SXin Li<!--#include virtual="menu.html.incl"--> 23*67e74705SXin Li 24*67e74705SXin Li<div id="content"> 25*67e74705SXin Li 26*67e74705SXin Li 27*67e74705SXin Li<!--=======================================================================--> 28*67e74705SXin Li<h1>Expressive Diagnostics</h1> 29*67e74705SXin Li<!--=======================================================================--> 30*67e74705SXin Li 31*67e74705SXin Li<p>In addition to being fast and functional, we aim to make Clang extremely user 32*67e74705SXin Lifriendly. As far as a command-line compiler goes, this basically boils down to 33*67e74705SXin Limaking the diagnostics (error and warning messages) generated by the compiler 34*67e74705SXin Libe as useful as possible. There are several ways that we do this. This section 35*67e74705SXin Litalks about the experience provided by the command line compiler, contrasting 36*67e74705SXin LiClang output to GCC 4.9's output in some cases. 37*67e74705SXin Li</p> 38*67e74705SXin Li 39*67e74705SXin Li<h2>Column Numbers and Caret Diagnostics</h2> 40*67e74705SXin Li 41*67e74705SXin Li<p>First, all diagnostics produced by clang include full column number 42*67e74705SXin Liinformation. The clang command-line compiler driver uses this information 43*67e74705SXin Lito print "point diagnostics". 44*67e74705SXin Li(IDEs can use the information to display in-line error markup.) 45*67e74705SXin LiThis is nice because it makes it very easy to understand exactly 46*67e74705SXin Liwhat is wrong in a particular piece of code.</p> 47*67e74705SXin Li 48*67e74705SXin Li<p>The point (the green "^" character) exactly shows where the problem is, even 49*67e74705SXin Liinside of a string. This makes it really easy to jump to the problem and 50*67e74705SXin Lihelps when multiple instances of the same character occur on a line. (We'll 51*67e74705SXin Lirevisit this more in following examples.)</p> 52*67e74705SXin Li 53*67e74705SXin Li<pre> 54*67e74705SXin Li $ <span class="cmd">gcc-4.9 -fsyntax-only -Wformat format-strings.c</span> 55*67e74705SXin Li format-strings.c: In function 'void f()': 56*67e74705SXin Li format-strings.c:91:16: warning: field precision specifier '.*' expects a matching 'int' argument [-Wformat=] 57*67e74705SXin Li printf("%.*d"); 58*67e74705SXin Li ^ 59*67e74705SXin Li format-strings.c:91:16: warning: format '%d' expects a matching 'int' argument [-Wformat=] 60*67e74705SXin Li $ <span class="cmd">clang -fsyntax-only format-strings.c</span> 61*67e74705SXin Li <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> 62*67e74705SXin Li <span class="snip" > printf("%.*d");</span> 63*67e74705SXin Li <span class="point"> ^</span> 64*67e74705SXin Li</pre> 65*67e74705SXin Li 66*67e74705SXin Li<p>Note that modern versions of GCC have followed Clang's lead, and are 67*67e74705SXin Linow able to give a column for a diagnostic, and include a snippet of source 68*67e74705SXin Litext in the result. However, Clang's column number is much more accurate, 69*67e74705SXin Lipointing at the problematic format specifier, rather than the <tt>)</tt> 70*67e74705SXin Licharacter the parser had reached when the problem was detected. 71*67e74705SXin LiAlso, Clang's diagnostic is colored by default, making it easier to 72*67e74705SXin Lidistinguish from nearby text.</p> 73*67e74705SXin Li 74*67e74705SXin Li<h2>Range Highlighting for Related Text</h2> 75*67e74705SXin Li 76*67e74705SXin Li<p>Clang captures and accurately tracks range information for expressions, 77*67e74705SXin Listatements, and other constructs in your program and uses this to make 78*67e74705SXin Lidiagnostics highlight related information. In the following somewhat 79*67e74705SXin Linonsensical example you can see that you don't even need to see the original source code to 80*67e74705SXin Liunderstand what is wrong based on the Clang error. Because clang prints a 81*67e74705SXin Lipoint, you know exactly <em>which</em> plus it is complaining about. The range 82*67e74705SXin Liinformation highlights the left and right side of the plus which makes it 83*67e74705SXin Liimmediately obvious what the compiler is talking about. 84*67e74705SXin LiRange information is very useful for 85*67e74705SXin Licases involving precedence issues and many other cases.</p> 86*67e74705SXin Li 87*67e74705SXin Li<pre> 88*67e74705SXin Li $ <span class="cmd">gcc-4.9 -fsyntax-only t.c</span> 89*67e74705SXin Li t.c: In function 'int f(int, int)': 90*67e74705SXin Li t.c:7:39: error: invalid operands to binary + (have 'int' and 'struct A') 91*67e74705SXin Li return y + func(y ? ((SomeA.X + 40) + SomeA) / 42 + SomeA.X : SomeA.X); 92*67e74705SXin Li ^ 93*67e74705SXin Li $ <span class="cmd">clang -fsyntax-only t.c</span> 94*67e74705SXin Li <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> 95*67e74705SXin Li <span class="snip" > return y + func(y ? ((SomeA.X + 40) + SomeA) / 42 + SomeA.X : SomeA.X);</span> 96*67e74705SXin Li <span class="point"> ~~~~~~~~~~~~~~ ^ ~~~~~</span> 97*67e74705SXin Li</pre> 98*67e74705SXin Li 99*67e74705SXin Li<h2>Precision in Wording</h2> 100*67e74705SXin Li 101*67e74705SXin Li<p>A detail is that we have tried really hard to make the diagnostics that come 102*67e74705SXin Liout of clang contain exactly the pertinent information about what is wrong and 103*67e74705SXin Liwhy. In the example above, we tell you what the inferred types are for 104*67e74705SXin Lithe left and right hand sides, and we don't repeat what is obvious from the 105*67e74705SXin Lipoint (e.g., that this is a "binary +").</p> 106*67e74705SXin Li 107*67e74705SXin Li<p>Many other examples abound. In the following example, not only do we tell you 108*67e74705SXin Lithat there is a problem with the <tt>*</tt> 109*67e74705SXin Liand point to it, we say exactly why and tell you what the type is (in case it is 110*67e74705SXin Lia complicated subexpression, such as a call to an overloaded function). This 111*67e74705SXin Lisort of attention to detail makes it much easier to understand and fix problems 112*67e74705SXin Liquickly.</p> 113*67e74705SXin Li 114*67e74705SXin Li<pre> 115*67e74705SXin Li $ <span class="cmd">gcc-4.9 -fsyntax-only t.c</span> 116*67e74705SXin Li t.c:5:11: error: invalid type argument of unary '*' (have 'int') 117*67e74705SXin Li return *SomeA.X; 118*67e74705SXin Li ^ 119*67e74705SXin Li $ <span class="cmd">clang -fsyntax-only t.c</span> 120*67e74705SXin Li <span class="loc">t.c:5:11:</span> <span class="err">error:</span> <span class="msg">indirection requires pointer operand ('int' invalid)</span> 121*67e74705SXin Li <span class="snip" > int y = *SomeA.X;</span> 122*67e74705SXin Li <span class="point"> ^~~~~~~~</span> 123*67e74705SXin Li</pre> 124*67e74705SXin Li 125*67e74705SXin Li<h2>Typedef Preservation and Selective Unwrapping</h2> 126*67e74705SXin Li 127*67e74705SXin Li<p>Many programmers use high-level user defined types, typedefs, and other 128*67e74705SXin Lisyntactic sugar to refer to types in their program. This is useful because they 129*67e74705SXin Lican abbreviate otherwise very long types and it is useful to preserve the 130*67e74705SXin Litypename in diagnostics. However, sometimes very simple typedefs can wrap 131*67e74705SXin Litrivial types and it is important to strip off the typedef to understand what 132*67e74705SXin Liis going on. Clang aims to handle both cases well.<p> 133*67e74705SXin Li 134*67e74705SXin Li<p>The following example shows where it is important to preserve 135*67e74705SXin Lia typedef in C.</p> 136*67e74705SXin Li 137*67e74705SXin Li<pre> 138*67e74705SXin Li $ <span class="cmd">clang -fsyntax-only t.c</span> 139*67e74705SXin Li <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> 140*67e74705SXin Li <span class="snip"> myvec[1]/P;</span> 141*67e74705SXin Li <span class="point"> ~~~~~~~~^~</span> 142*67e74705SXin Li</pre> 143*67e74705SXin Li 144*67e74705SXin Li<p>The following example shows where it is useful for the compiler to expose 145*67e74705SXin Liunderlying details of a typedef. If the user was somehow confused about how the 146*67e74705SXin Lisystem "pid_t" typedef is defined, Clang helpfully displays it with "aka".</p> 147*67e74705SXin Li 148*67e74705SXin Li<pre> 149*67e74705SXin Li $ <span class="cmd">clang -fsyntax-only t.c</span> 150*67e74705SXin Li <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> 151*67e74705SXin Li <span class="snip"> myvar = myvar.x;</span> 152*67e74705SXin Li <span class="point"> ~~~~~ ^</span> 153*67e74705SXin Li</pre> 154*67e74705SXin Li 155*67e74705SXin Li<p>In C++, type preservation includes retaining any qualification written into type names. For example, if we take a small snippet of code such as: 156*67e74705SXin Li 157*67e74705SXin Li<blockquote> 158*67e74705SXin Li<pre> 159*67e74705SXin Linamespace services { 160*67e74705SXin Li struct WebService { }; 161*67e74705SXin Li} 162*67e74705SXin Linamespace myapp { 163*67e74705SXin Li namespace servers { 164*67e74705SXin Li struct Server { }; 165*67e74705SXin Li } 166*67e74705SXin Li} 167*67e74705SXin Li 168*67e74705SXin Liusing namespace myapp; 169*67e74705SXin Livoid addHTTPService(servers::Server const &server, ::services::WebService const *http) { 170*67e74705SXin Li server += http; 171*67e74705SXin Li} 172*67e74705SXin Li</pre> 173*67e74705SXin Li</blockquote> 174*67e74705SXin Li 175*67e74705SXin Li<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"): 176*67e74705SXin Li 177*67e74705SXin Li<pre> 178*67e74705SXin Li $ <span class="cmd">clang -fsyntax-only t.cpp</span> 179*67e74705SXin Li <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> 180*67e74705SXin Li <span class="snip">server += http;</span> 181*67e74705SXin Li <span class="point">~~~~~~ ^ ~~~~</span> 182*67e74705SXin Li</pre> 183*67e74705SXin Li 184*67e74705SXin Li<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> 185*67e74705SXin Li 186*67e74705SXin Li<pre> 187*67e74705SXin Li $ <span class="cmd">clang -fsyntax-only t.cpp</span> 188*67e74705SXin Li <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> 189*67e74705SXin Li <span class="snip">str = vec</span>; 190*67e74705SXin Li <span class="point">^ ~~~</span> 191*67e74705SXin Li</pre> 192*67e74705SXin Li 193*67e74705SXin Li<h2>Fix-it Hints</h2> 194*67e74705SXin Li 195*67e74705SXin Li<p>"Fix-it" hints provide advice for fixing small, localized problems 196*67e74705SXin Liin source code. When Clang produces a diagnostic about a particular 197*67e74705SXin Liproblem that it can work around (e.g., non-standard or redundant 198*67e74705SXin Lisyntax, missing keywords, common mistakes, etc.), it may also provide 199*67e74705SXin Lispecific guidance in the form of a code transformation to correct the 200*67e74705SXin Liproblem. In the following example, Clang warns about the use of a GCC 201*67e74705SXin Liextension that has been considered obsolete since 1993. The underlined 202*67e74705SXin Licode should be removed, then replaced with the code below the 203*67e74705SXin Lipoint line (".x =" or ".y =", respectively).</p> 204*67e74705SXin Li 205*67e74705SXin Li<pre> 206*67e74705SXin Li $ <span class="cmd">clang t.c</span> 207*67e74705SXin Li <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> 208*67e74705SXin Li <span class="snip">struct point origin = { x: 0.0, y: 0.0 };</span> 209*67e74705SXin Li <span class="err">~~</span> <span class="msg"><span class="point">^</span></span> 210*67e74705SXin Li <span class="snip">.x = </span> 211*67e74705SXin Li <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> 212*67e74705SXin Li <span class="snip">struct point origin = { x: 0.0, y: 0.0 };</span> 213*67e74705SXin Li <span class="err">~~</span> <span class="msg"><span class="point">^</span></span> 214*67e74705SXin Li <span class="snip">.y = </span> 215*67e74705SXin Li</pre> 216*67e74705SXin Li 217*67e74705SXin Li<p>"Fix-it" hints are most useful for 218*67e74705SXin Liworking around common user errors and misconceptions. For example, C++ users 219*67e74705SXin Licommonly forget the syntax for explicit specialization of class templates, 220*67e74705SXin Lias in the error in the following example. Again, after describing the problem, 221*67e74705SXin LiClang provides the fix--add <code>template<></code>--as part of the 222*67e74705SXin Lidiagnostic.<p> 223*67e74705SXin Li 224*67e74705SXin Li<pre> 225*67e74705SXin Li $ <span class="cmd">clang t.cpp</span> 226*67e74705SXin Li <span class="loc">t.cpp:9:3:</span> <span class="err">error:</span> <span class="msg">template specialization requires 'template<>'</span> 227*67e74705SXin Li struct iterator_traits<file_iterator> { 228*67e74705SXin Li <span class="point">^</span> 229*67e74705SXin Li <span class="snip">template<> </span> 230*67e74705SXin Li</pre> 231*67e74705SXin Li 232*67e74705SXin Li<h2>Template Type Diffing</h2> 233*67e74705SXin Li 234*67e74705SXin Li<p>Templates types can be long and difficult to read. Moreso when part of an 235*67e74705SXin Lierror message. Instead of just printing out the type name, Clang has enough 236*67e74705SXin Liinformation to remove the common elements and highlight the differences. To 237*67e74705SXin Lishow the template structure more clearly, the templated type can also be 238*67e74705SXin Liprinted as an indented text tree.</p> 239*67e74705SXin Li 240*67e74705SXin LiDefault: template diff with type elision 241*67e74705SXin Li<pre> 242*67e74705SXin Li<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; 243*67e74705SXin Li</pre> 244*67e74705SXin Li-fno-elide-type: template diff without elision 245*67e74705SXin Li<pre> 246*67e74705SXin Li<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; 247*67e74705SXin Li</pre> 248*67e74705SXin Li-fdiagnostics-show-template-tree: template tree printing with elision 249*67e74705SXin Li<pre> 250*67e74705SXin Li<span class="loc">t.cc:4:5:</span> <span class="note">note:</span> candidate function not viable: no known conversion for 1st argument; 251*67e74705SXin Li vector< 252*67e74705SXin Li map< 253*67e74705SXin Li [...], 254*67e74705SXin Li [<span class="template-highlight">float</span> != <span class="template-highlight">double</span>]>> 255*67e74705SXin Li</pre> 256*67e74705SXin Li-fdiagnostics-show-template-tree -fno-elide-type: template tree printing with no elision 257*67e74705SXin Li<pre> 258*67e74705SXin Li<span class="loc">t.cc:4:5:</span> <span class="note">note:</span> candidate function not viable: no known conversion for 1st argument; 259*67e74705SXin Li vector< 260*67e74705SXin Li map< 261*67e74705SXin Li int, 262*67e74705SXin Li [<span class="template-highlight">float</span> != <span class="template-highlight">double</span>]>> 263*67e74705SXin Li</pre> 264*67e74705SXin Li 265*67e74705SXin Li<h2>Automatic Macro Expansion</h2> 266*67e74705SXin Li 267*67e74705SXin Li<p>Many errors happen in macros that are sometimes deeply nested. With 268*67e74705SXin Litraditional compilers, you need to dig deep into the definition of the macro to 269*67e74705SXin Liunderstand how you got into trouble. The following simple example shows how 270*67e74705SXin LiClang helps you out by automatically printing instantiation information and 271*67e74705SXin Linested range information for diagnostics as they are instantiated through macros 272*67e74705SXin Liand also shows how some of the other pieces work in a bigger example.</p> 273*67e74705SXin Li 274*67e74705SXin Li<pre> 275*67e74705SXin Li $ <span class="cmd">clang -fsyntax-only t.c</span> 276*67e74705SXin Li <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> 277*67e74705SXin Li <span class="snip"> X = MYMAX(P, F);</span> 278*67e74705SXin Li <span class="point"> ^~~~~~~~~~~</span> 279*67e74705SXin Li <span class="loc">t.c:76:94:</span> <span class="note">note:</span> expanded from: 280*67e74705SXin Li <span class="snip">#define MYMAX(A,B) __extension__ ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __b : __a; })</span> 281*67e74705SXin Li <span class="point"> ~~~ ^ ~~~</span> 282*67e74705SXin Li</pre> 283*67e74705SXin Li 284*67e74705SXin Li<p>Here's another real world warning that occurs in the "window" Unix package (which 285*67e74705SXin Liimplements the "wwopen" class of APIs):</p> 286*67e74705SXin Li 287*67e74705SXin Li<pre> 288*67e74705SXin Li $ <span class="cmd">clang -fsyntax-only t.c</span> 289*67e74705SXin Li <span class="loc">t.c:22:2:</span> <span class="warn">warning:</span> <span class="msg">type specifier missing, defaults to 'int'</span> 290*67e74705SXin Li <span class="snip"> ILPAD();</span> 291*67e74705SXin Li <span class="point"> ^</span> 292*67e74705SXin Li <span class="loc">t.c:17:17:</span> <span class="note">note:</span> expanded from: 293*67e74705SXin Li <span class="snip">#define ILPAD() PAD((NROW - tt.tt_row) * 10) /* 1 ms per char */</span> 294*67e74705SXin Li <span class="point"> ^</span> 295*67e74705SXin Li <span class="loc">t.c:14:2:</span> <span class="note">note:</span> expanded from: 296*67e74705SXin Li <span class="snip"> register i; \</span> 297*67e74705SXin Li <span class="point"> ^</span> 298*67e74705SXin Li</pre> 299*67e74705SXin Li 300*67e74705SXin Li<p>In practice, we've found that Clang's treatment of macros is actually more useful in multiply nested 301*67e74705SXin Limacros that in simple ones.</p> 302*67e74705SXin Li 303*67e74705SXin Li<h2>Quality of Implementation and Attention to Detail</h2> 304*67e74705SXin Li 305*67e74705SXin Li<p>Finally, we have put a lot of work polishing the little things, because 306*67e74705SXin Lilittle things add up over time and contribute to a great user experience.</p> 307*67e74705SXin Li 308*67e74705SXin Li<p>The following example shows that we recover from the simple case of 309*67e74705SXin Liforgetting a ; after a struct definition much better than GCC.</p> 310*67e74705SXin Li 311*67e74705SXin Li<pre> 312*67e74705SXin Li $ <span class="cmd">cat t.cc</span> 313*67e74705SXin Li template<class T> 314*67e74705SXin Li class a {}; 315*67e74705SXin Li struct b {} 316*67e74705SXin Li a<int> c; 317*67e74705SXin Li $ <span class="cmd">gcc-4.9 t.cc</span> 318*67e74705SXin Li t.cc:4:8: error: invalid declarator before 'c' 319*67e74705SXin Li a<int> c; 320*67e74705SXin Li ^ 321*67e74705SXin Li $ <span class="cmd">clang t.cc</span> 322*67e74705SXin Li <span class="loc">t.cc:3:12:</span> <span class="err">error:</span> <span class="msg">expected ';' after struct</span> 323*67e74705SXin Li <span class="snip" >struct b {}</span> 324*67e74705SXin Li <span class="point"> ^</span> 325*67e74705SXin Li <span class="point"> ;</span> 326*67e74705SXin Li</pre> 327*67e74705SXin Li 328*67e74705SXin Li<p>The following example shows that we diagnose and recover from a missing 329*67e74705SXin Li<tt>typename</tt> keyword well, even in complex circumstances where GCC 330*67e74705SXin Licannot cope.</p> 331*67e74705SXin Li 332*67e74705SXin Li<pre> 333*67e74705SXin Li $ <span class="cmd">cat t.cc</span> 334*67e74705SXin Li template<class T> void f(T::type) { } 335*67e74705SXin Li struct A { }; 336*67e74705SXin Li void g() 337*67e74705SXin Li { 338*67e74705SXin Li A a; 339*67e74705SXin Li f<A>(a); 340*67e74705SXin Li } 341*67e74705SXin Li $ <span class="cmd">gcc-4.9 t.cc</span> 342*67e74705SXin Li t.cc:1:33: error: variable or field 'f' declared void 343*67e74705SXin Li template<class T> void f(T::type) { } 344*67e74705SXin Li ^ 345*67e74705SXin Li t.cc: In function 'void g()': 346*67e74705SXin Li t.cc:6:5: error: 'f' was not declared in this scope 347*67e74705SXin Li f<A>(a); 348*67e74705SXin Li ^ 349*67e74705SXin Li t.cc:6:8: error: expected primary-expression before '>' token 350*67e74705SXin Li f<A>(a); 351*67e74705SXin Li ^ 352*67e74705SXin Li $ <span class="cmd">clang t.cc</span> 353*67e74705SXin Li <span class="loc">t.cc:1:26:</span> <span class="err">error:</span> <span class="msg">missing 'typename' prior to dependent type name 'T::type'</span> 354*67e74705SXin Li <span class="snip" >template<class T> void f(T::type) { }</span> 355*67e74705SXin Li <span class="point"> ^~~~~~~</span> 356*67e74705SXin Li <span class="point"> typename </span> 357*67e74705SXin Li <span class="loc">t.cc:6:5:</span> <span class="err">error:</span> <span class="msg">no matching function for call to 'f'</span> 358*67e74705SXin Li <span class="snip" > f<A>(a);</span> 359*67e74705SXin Li <span class="point"> ^~~~</span> 360*67e74705SXin Li <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> 361*67e74705SXin Li <span class="snip" >template<class T> void f(T::type) { }</span> 362*67e74705SXin Li <span class="point"> ^ ~~~~</span> 363*67e74705SXin Li</pre> 364*67e74705SXin Li 365*67e74705SXin Li 366*67e74705SXin Li 367*67e74705SXin Li<p>While each of these details is minor, we feel that they all add up to provide 368*67e74705SXin Lia much more polished experience.</p> 369*67e74705SXin Li 370*67e74705SXin Li</div> 371*67e74705SXin Li</body> 372*67e74705SXin Li</html> 373