1*4c3eb207Smrg@c Copyright (C) 2018-2020 Free Software Foundation, Inc. 2627f7eb2Smrg@c Free Software Foundation, Inc. 3627f7eb2Smrg@c This is part of the GCC manual. 4627f7eb2Smrg@c For copying conditions, see the file gcc.texi. 5627f7eb2Smrg 6627f7eb2Smrg@node User Experience Guidelines 7627f7eb2Smrg@chapter User Experience Guidelines 8627f7eb2Smrg@cindex user experience guidelines 9627f7eb2Smrg@cindex guidelines, user experience 10627f7eb2Smrg 11627f7eb2SmrgTo borrow a slogan from 12*4c3eb207Smrg@uref{https://elm-lang.org/news/compilers-as-assistants, Elm}, 13627f7eb2Smrg 14627f7eb2Smrg@quotation 15627f7eb2Smrg@strong{Compilers should be assistants, not adversaries.} A compiler should 16627f7eb2Smrgnot just detect bugs, it should then help you understand why there is a bug. 17627f7eb2SmrgIt should not berate you in a robot voice, it should give you specific hints 18627f7eb2Smrgthat help you write better code. Ultimately, a compiler should make 19627f7eb2Smrgprogramming faster and more fun! 20627f7eb2Smrg@author Evan Czaplicki 21627f7eb2Smrg@end quotation 22627f7eb2Smrg 23627f7eb2SmrgThis chapter provides guidelines on how to implement diagnostics and 24627f7eb2Smrgcommand-line options in ways that we hope achieve the above ideal. 25627f7eb2Smrg 26627f7eb2Smrg@menu 27627f7eb2Smrg* Guidelines for Diagnostics:: How to implement diagnostics. 28627f7eb2Smrg* Guidelines for Options:: Guidelines for command-line options. 29627f7eb2Smrg@end menu 30627f7eb2Smrg 31627f7eb2Smrg 32627f7eb2Smrg@node Guidelines for Diagnostics 33627f7eb2Smrg@section Guidelines for Diagnostics 34627f7eb2Smrg@cindex guidelines for diagnostics 35627f7eb2Smrg@cindex diagnostics, guidelines for 36627f7eb2Smrg 37627f7eb2Smrg@subsection Talk in terms of the user's code 38627f7eb2Smrg 39627f7eb2SmrgDiagnostics should be worded in terms of the user's source code, and the 40627f7eb2Smrgsource language, rather than GCC's own implementation details. 41627f7eb2Smrg 42627f7eb2Smrg@subsection Diagnostics are actionable 43627f7eb2Smrg@cindex diagnostics, actionable 44627f7eb2Smrg 45627f7eb2SmrgA good diagnostic is @dfn{actionable}: it should assist the user in 46627f7eb2Smrgtaking action. 47627f7eb2Smrg 48627f7eb2SmrgConsider what an end user will want to do when encountering a diagnostic. 49627f7eb2Smrg 50627f7eb2SmrgGiven an error, an end user will think: ``How do I fix this?'' 51627f7eb2Smrg 52627f7eb2SmrgGiven a warning, an end user will think: 53627f7eb2Smrg 54627f7eb2Smrg@itemize @bullet 55627f7eb2Smrg@item 56627f7eb2Smrg``Is this a real problem?'' 57627f7eb2Smrg@item 58627f7eb2Smrg``Do I care?'' 59627f7eb2Smrg@item 60627f7eb2Smrgif they decide it's genuine: ``How do I fix this?'' 61627f7eb2Smrg@end itemize 62627f7eb2Smrg 63627f7eb2SmrgA good diagnostic provides pertinent information to allow the user to 64627f7eb2Smrgeasily answer the above questions. 65627f7eb2Smrg 66627f7eb2Smrg@subsection The user's attention is important 67627f7eb2Smrg 68627f7eb2SmrgA perfect compiler would issue a warning on every aspect of the user's 69627f7eb2Smrgsource code that ought to be fixed, and issue no other warnings. 70627f7eb2SmrgNaturally, this ideal is impossible to achieve. 71627f7eb2Smrg 72627f7eb2Smrg@cindex signal-to-noise ratio (metaphorical usage for diagnostics) 73627f7eb2Smrg@cindex diagnostics, false positive 74627f7eb2Smrg@cindex diagnostics, true positive 75627f7eb2Smrg@cindex false positive 76627f7eb2Smrg@cindex true positive 77627f7eb2Smrg 78627f7eb2SmrgWarnings should have a good @dfn{signal-to-noise ratio}: we should have few 79627f7eb2Smrg@dfn{false positives} (falsely issuing a warning when no warning is 80627f7eb2Smrgwarranted) and few @dfn{false negatives} (failing to issue a warning when 81627f7eb2Smrgone @emph{is} justified). 82627f7eb2Smrg 83627f7eb2SmrgNote that a false positive can mean, in practice, a warning that the 84627f7eb2Smrguser doesn't agree with. Ideally a diagnostic should contain enough 85627f7eb2Smrginformation to allow the user to make an informed choice about whether 86627f7eb2Smrgthey should care (and how to fix it), but a balance must be drawn against 87627f7eb2Smrgoverloading the user with irrelevant data. 88627f7eb2Smrg 89627f7eb2Smrg@subsection Precision of Wording 90627f7eb2Smrg 91627f7eb2SmrgProvide the user with details that allow them to identify what the 92627f7eb2Smrgproblem is. For example, the vaguely-worded message: 93627f7eb2Smrg 94627f7eb2Smrg@smallexample 95627f7eb2Smrgdemo.c:1:1: warning: 'noinline' attribute ignored [-Wattributes] 96627f7eb2Smrg 1 | int foo __attribute__((noinline)); 97627f7eb2Smrg | ^~~ 98627f7eb2Smrg@end smallexample 99627f7eb2Smrg 100627f7eb2Smrg@noindent 101627f7eb2Smrgdoesn't tell the user why the attribute was ignored, or what kind of 102627f7eb2Smrgentity the compiler thought the attribute was being applied to (the 103627f7eb2Smrgsource location for the diagnostic is also poor; 104627f7eb2Smrg@pxref{input_location_example,,discussion of @code{input_location}}). 105627f7eb2SmrgA better message would be: 106627f7eb2Smrg 107627f7eb2Smrg@smallexample 108627f7eb2Smrgdemo.c:1:24: warning: attribute 'noinline' on variable 'foo' was 109627f7eb2Smrg ignored [-Wattributes] 110627f7eb2Smrg 1 | int foo __attribute__((noinline)); 111627f7eb2Smrg | ~~~ ~~~~~~~~~~~~~~~^~~~~~~~~ 112627f7eb2Smrgdemo.c:1:24: note: attribute 'noinline' is only applicable to functions 113627f7eb2Smrg@end smallexample 114627f7eb2Smrg 115627f7eb2Smrg@noindent 116627f7eb2Smrgwhich spells out the missing information (and fixes the location 117627f7eb2Smrginformation, as discussed below). 118627f7eb2Smrg 119627f7eb2SmrgThe above example uses a note to avoid a combinatorial explosion of possible 120627f7eb2Smrgmessages. 121627f7eb2Smrg 122627f7eb2Smrg@subsection Try the diagnostic on real-world code 123627f7eb2Smrg 124627f7eb2SmrgIt's worth testing a new warning on many instances of real-world code, 125627f7eb2Smrgwritten by different people, and seeing what it complains about, and 126627f7eb2Smrgwhat it doesn't complain about. 127627f7eb2Smrg 128627f7eb2SmrgThis may suggest heuristics that silence common false positives. 129627f7eb2Smrg 130627f7eb2SmrgIt may also suggest ways to improve the precision of the message. 131627f7eb2Smrg 132627f7eb2Smrg@subsection Make mismatches clear 133627f7eb2Smrg 134627f7eb2SmrgMany diagnostics relate to a mismatch between two different places in the 135627f7eb2Smrguser's source code. Examples include: 136627f7eb2Smrg@itemize @bullet 137627f7eb2Smrg @item 138627f7eb2Smrg a type mismatch, where the type at a usage site does not match the type 139627f7eb2Smrg at a declaration 140627f7eb2Smrg 141627f7eb2Smrg @item 142627f7eb2Smrg the argument count at a call site does not match the parameter count 143627f7eb2Smrg at the declaration 144627f7eb2Smrg 145627f7eb2Smrg @item 146627f7eb2Smrg something is erroneously duplicated (e.g.@: an error, due to breaking a 147627f7eb2Smrg uniqueness requirement, or a warning, if it's suggestive of a bug) 148627f7eb2Smrg 149627f7eb2Smrg @item 150627f7eb2Smrg an ``opened'' syntactic construct (such as an open-parenthesis) is not 151627f7eb2Smrg closed 152627f7eb2Smrg 153627f7eb2Smrg @c TODO: more examples? 154627f7eb2Smrg@end itemize 155627f7eb2Smrg 156627f7eb2SmrgIn each case, the diagnostic should indicate @strong{both} pertinent 157627f7eb2Smrglocations (so that the user can easily see the problem and how to fix it). 158627f7eb2Smrg 159627f7eb2SmrgThe standard way to do this is with a note (via @code{inform}). For 160627f7eb2Smrgexample: 161627f7eb2Smrg 162627f7eb2Smrg@smallexample 163627f7eb2Smrg auto_diagnostic_group d; 164627f7eb2Smrg if (warning_at (loc, OPT_Wduplicated_cond, 165627f7eb2Smrg "duplicated %<if%> condition")) 166627f7eb2Smrg inform (EXPR_LOCATION (t), "previously used here"); 167627f7eb2Smrg@end smallexample 168627f7eb2Smrg 169627f7eb2Smrg@noindent 170627f7eb2Smrgwhich leads to: 171627f7eb2Smrg 172627f7eb2Smrg@smallexample 173627f7eb2Smrgdemo.c: In function 'test': 174627f7eb2Smrgdemo.c:5:17: warning: duplicated 'if' condition [-Wduplicated-cond] 175627f7eb2Smrg 5 | else if (flag > 3) 176627f7eb2Smrg | ~~~~~^~~ 177627f7eb2Smrgdemo.c:3:12: note: previously used here 178627f7eb2Smrg 3 | if (flag > 3) 179627f7eb2Smrg | ~~~~~^~~ 180627f7eb2Smrg@end smallexample 181627f7eb2Smrg 182627f7eb2Smrg@noindent 183627f7eb2SmrgThe @code{inform} call should be guarded by the return value from the 184627f7eb2Smrg@code{warning_at} call so that the note isn't emitted when the warning 185627f7eb2Smrgis suppressed. 186627f7eb2Smrg 187627f7eb2SmrgFor cases involving punctuation where the locations might be near 188627f7eb2Smrgeach other, they can be conditionally consolidated via 189627f7eb2Smrg@code{gcc_rich_location::add_location_if_nearby}: 190627f7eb2Smrg 191627f7eb2Smrg@smallexample 192627f7eb2Smrg auto_diagnostic_group d; 193627f7eb2Smrg gcc_rich_location richloc (primary_loc); 194627f7eb2Smrg bool added secondary = richloc.add_location_if_nearby (secondary_loc); 195627f7eb2Smrg error_at (&richloc, "main message"); 196627f7eb2Smrg if (!added secondary) 197627f7eb2Smrg inform (secondary_loc, "message for secondary"); 198627f7eb2Smrg@end smallexample 199627f7eb2Smrg 200627f7eb2Smrg@noindent 201627f7eb2SmrgThis will emit either one diagnostic with two locations: 202627f7eb2Smrg@smallexample 203627f7eb2Smrg demo.c:42:10: error: main message 204627f7eb2Smrg (foo) 205627f7eb2Smrg ~ ^ 206627f7eb2Smrg@end smallexample 207627f7eb2Smrg 208627f7eb2Smrg@noindent 209627f7eb2Smrgor two diagnostics: 210627f7eb2Smrg 211627f7eb2Smrg@smallexample 212627f7eb2Smrg demo.c:42:4: error: main message 213627f7eb2Smrg foo) 214627f7eb2Smrg ^ 215627f7eb2Smrg demo.c:40:2: note: message for secondary 216627f7eb2Smrg ( 217627f7eb2Smrg ^ 218627f7eb2Smrg@end smallexample 219627f7eb2Smrg 220627f7eb2Smrg@subsection Location Information 221627f7eb2Smrg@cindex diagnostics, locations 222627f7eb2Smrg@cindex location information 223627f7eb2Smrg@cindex source code, location information 224627f7eb2Smrg@cindex caret 225627f7eb2Smrg 226627f7eb2SmrgGCC's @code{location_t} type can support both ordinary locations, 227627f7eb2Smrgand locations relating to a macro expansion. 228627f7eb2Smrg 229627f7eb2SmrgAs of GCC 6, ordinary locations changed from supporting just a 230627f7eb2Smrgpoint in the user's source code to supporting three points: the 231627f7eb2Smrg@dfn{caret} location, plus a start and a finish: 232627f7eb2Smrg 233627f7eb2Smrg@smallexample 234627f7eb2Smrg a = foo && bar; 235627f7eb2Smrg ~~~~^~~~~~ 236627f7eb2Smrg | | | 237627f7eb2Smrg | | finish 238627f7eb2Smrg | caret 239627f7eb2Smrg start 240627f7eb2Smrg@end smallexample 241627f7eb2Smrg 242627f7eb2SmrgTokens coming out of libcpp have locations of the form @code{caret == start}, 243627f7eb2Smrgsuch as for @code{foo} here: 244627f7eb2Smrg 245627f7eb2Smrg@smallexample 246627f7eb2Smrg a = foo && bar; 247627f7eb2Smrg ^~~ 248627f7eb2Smrg | | 249627f7eb2Smrg | finish 250627f7eb2Smrg caret == start 251627f7eb2Smrg@end smallexample 252627f7eb2Smrg 253627f7eb2SmrgCompound expressions should be reported using the location of the 254627f7eb2Smrgexpression as a whole, rather than just of one token within it. 255627f7eb2Smrg 256627f7eb2SmrgFor example, in @code{-Wformat}, rather than underlining just the first 257627f7eb2Smrgtoken of a bad argument: 258627f7eb2Smrg 259627f7eb2Smrg@smallexample 260627f7eb2Smrg printf("hello %i %s", (long)0, "world"); 261627f7eb2Smrg ~^ ~ 262627f7eb2Smrg %li 263627f7eb2Smrg@end smallexample 264627f7eb2Smrg 265627f7eb2Smrg@noindent 266627f7eb2Smrgthe whole of the expression should be underlined, so that the user can 267627f7eb2Smrgeasily identify what is being referred to: 268627f7eb2Smrg 269627f7eb2Smrg@smallexample 270627f7eb2Smrg printf("hello %i %s", (long)0, "world"); 271627f7eb2Smrg ~^ ~~~~~~~ 272627f7eb2Smrg %li 273627f7eb2Smrg@end smallexample 274627f7eb2Smrg 275627f7eb2Smrg@c this was r251239 276627f7eb2Smrg 277627f7eb2SmrgAvoid using the @code{input_location} global, and the diagnostic functions 278627f7eb2Smrgthat implicitly use it---use @code{error_at} and @code{warning_at} rather 279627f7eb2Smrgthan @code{error} and @code{warning}, and provide the most appropriate 280627f7eb2Smrg@code{location_t} value available at that phase of the compilation. It's 281627f7eb2Smrgpossible to supply secondary @code{location_t} values via 282627f7eb2Smrg@code{rich_location}. 283627f7eb2Smrg 284627f7eb2Smrg@noindent 285627f7eb2Smrg@anchor{input_location_example} 286627f7eb2SmrgFor example, in the example of imprecise wording above, generating the 287627f7eb2Smrgdiagnostic using @code{warning}: 288627f7eb2Smrg 289627f7eb2Smrg@smallexample 290627f7eb2Smrg // BAD: implicitly uses @code{input_location} 291627f7eb2Smrg warning (OPT_Wattributes, "%qE attribute ignored", name); 292627f7eb2Smrg@end smallexample 293627f7eb2Smrg 294627f7eb2Smrg@noindent 295627f7eb2Smrgleads to: 296627f7eb2Smrg 297627f7eb2Smrg@smallexample 298627f7eb2Smrg// BAD: uses @code{input_location} 299627f7eb2Smrgdemo.c:1:1: warning: 'noinline' attribute ignored [-Wattributes] 300627f7eb2Smrg 1 | int foo __attribute__((noinline)); 301627f7eb2Smrg | ^~~ 302627f7eb2Smrg@end smallexample 303627f7eb2Smrg 304627f7eb2Smrg@noindent 305627f7eb2Smrgwhich thus happened to use the location of the @code{int} token, rather 306627f7eb2Smrgthan that of the attribute. Using @code{warning_at} with the location of 307627f7eb2Smrgthe attribute, providing the location of the declaration in question 308627f7eb2Smrgas a secondary location, and adding a note: 309627f7eb2Smrg 310627f7eb2Smrg@smallexample 311627f7eb2Smrg auto_diagnostic_group d; 312627f7eb2Smrg gcc_rich_location richloc (attrib_loc); 313627f7eb2Smrg richloc.add_range (decl_loc); 314627f7eb2Smrg if (warning_at (OPT_Wattributes, &richloc, 315627f7eb2Smrg "attribute %qE on variable %qE was ignored", name)) 316627f7eb2Smrg inform (attrib_loc, "attribute %qE is only applicable to functions"); 317627f7eb2Smrg@end smallexample 318627f7eb2Smrg 319627f7eb2Smrg@noindent 320627f7eb2Smrgwould lead to: 321627f7eb2Smrg 322627f7eb2Smrg@smallexample 323627f7eb2Smrg// OK: use location of attribute, with a secondary location 324627f7eb2Smrgdemo.c:1:24: warning: attribute 'noinline' on variable 'foo' was 325627f7eb2Smrg ignored [-Wattributes] 326627f7eb2Smrg 1 | int foo __attribute__((noinline)); 327627f7eb2Smrg | ~~~ ~~~~~~~~~~~~~~~^~~~~~~~~ 328627f7eb2Smrgdemo.c:1:24: note: attribute 'noinline' is only applicable to functions 329627f7eb2Smrg@end smallexample 330627f7eb2Smrg 331627f7eb2Smrg@c TODO labelling of ranges 332627f7eb2Smrg 333627f7eb2Smrg@subsection Coding Conventions 334627f7eb2Smrg 335627f7eb2SmrgSee the @uref{https://gcc.gnu.org/codingconventions.html#Diagnostics, 336627f7eb2Smrgdiagnostics section} of the GCC coding conventions. 337627f7eb2Smrg 338627f7eb2SmrgIn the C++ front end, when comparing two types in a message, use @samp{%H} 339627f7eb2Smrgand @samp{%I} rather than @samp{%T}, as this allows the diagnostics 340627f7eb2Smrgsubsystem to highlight differences between template-based types. 341627f7eb2SmrgFor example, rather than using @samp{%qT}: 342627f7eb2Smrg 343627f7eb2Smrg@smallexample 344627f7eb2Smrg // BAD: a pair of %qT used in C++ front end for type comparison 345627f7eb2Smrg error_at (loc, "could not convert %qE from %qT to %qT", expr, 346627f7eb2Smrg TREE_TYPE (expr), type); 347627f7eb2Smrg@end smallexample 348627f7eb2Smrg 349627f7eb2Smrg@noindent 350627f7eb2Smrgwhich could lead to: 351627f7eb2Smrg 352627f7eb2Smrg@smallexample 353627f7eb2Smrgerror: could not convert 'map<int, double>()' from 'map<int,double>' 354627f7eb2Smrg to 'map<int,int>' 355627f7eb2Smrg@end smallexample 356627f7eb2Smrg 357627f7eb2Smrg@noindent 358627f7eb2Smrgusing @samp{%H} and @samp{%I} (via @samp{%qH} and @samp{%qI}): 359627f7eb2Smrg 360627f7eb2Smrg@smallexample 361627f7eb2Smrg // OK: compare types in C++ front end via %qH and %qI 362627f7eb2Smrg error_at (loc, "could not convert %qE from %qH to %qI", expr, 363627f7eb2Smrg TREE_TYPE (expr), type); 364627f7eb2Smrg@end smallexample 365627f7eb2Smrg 366627f7eb2Smrg@noindent 367627f7eb2Smrgallows the above output to be simplified to: 368627f7eb2Smrg 369627f7eb2Smrg@smallexample 370627f7eb2Smrgerror: could not convert 'map<int, double>()' from 'map<[...],double>' 371627f7eb2Smrg to 'map<[...],int>' 372627f7eb2Smrg@end smallexample 373627f7eb2Smrg 374627f7eb2Smrg@noindent 375627f7eb2Smrgwhere the @code{double} and @code{int} are colorized to highlight them. 376627f7eb2Smrg 377627f7eb2Smrg@c %H and %I were added in r248698. 378627f7eb2Smrg 379627f7eb2Smrg@subsection Group logically-related diagnostics 380627f7eb2Smrg 381627f7eb2SmrgUse @code{auto_diagnostic_group} when issuing multiple related 382627f7eb2Smrgdiagnostics (seen in various examples on this page). This informs the 383627f7eb2Smrgdiagnostic subsystem that all diagnostics issued within the lifetime 384627f7eb2Smrgof the @code{auto_diagnostic_group} are related. For example, 385627f7eb2Smrg@option{-fdiagnostics-format=json} will treat the first diagnostic 386627f7eb2Smrgemitted within the group as a top-level diagnostic, and all subsequent 387627f7eb2Smrgdiagnostics within the group as its children. 388627f7eb2Smrg 389627f7eb2Smrg@subsection Quoting 390627f7eb2SmrgText should be quoted by either using the @samp{q} modifier in a directive 391627f7eb2Smrgsuch as @samp{%qE}, or by enclosing the quoted text in a pair of @samp{%<} 392627f7eb2Smrgand @samp{%>} directives, and never by using explicit quote characters. 393627f7eb2SmrgThe directives handle the appropriate quote characters for each language 394627f7eb2Smrgand apply the correct color or highlighting. 395627f7eb2Smrg 396627f7eb2SmrgThe following elements should be quoted in GCC diagnostics: 397627f7eb2Smrg 398627f7eb2Smrg@itemize @bullet 399627f7eb2Smrg@item 400627f7eb2SmrgLanguage keywords. 401627f7eb2Smrg@item 402627f7eb2SmrgTokens. 403627f7eb2Smrg@item 404627f7eb2SmrgBoolean, numerical, character, and string constants that appear in the 405627f7eb2Smrgsource code. 406627f7eb2Smrg@item 407627f7eb2SmrgIdentifiers, including function, macro, type, and variable names. 408627f7eb2Smrg@end itemize 409627f7eb2Smrg 410627f7eb2SmrgOther elements such as numbers that do not refer to numeric constants that 411627f7eb2Smrgappear in the source code should not be quoted. For example, in the message: 412627f7eb2Smrg 413627f7eb2Smrg@smallexample 414627f7eb2Smrgargument %d of %qE must be a pointer type 415627f7eb2Smrg@end smallexample 416627f7eb2Smrg 417627f7eb2Smrg@noindent 418627f7eb2Smrgsince the argument number does not refer to a numerical constant in the 419627f7eb2Smrgsource code it should not be quoted. 420627f7eb2Smrg 421627f7eb2Smrg@subsection Spelling and Terminology 422627f7eb2Smrg 423627f7eb2SmrgSee the @uref{https://gcc.gnu.org/codingconventions.html#Spelling 424627f7eb2SmrgSpelling, terminology and markup} section of the GCC coding conventions. 425627f7eb2Smrg 426627f7eb2Smrg@subsection Fix-it hints 427627f7eb2Smrg@cindex fix-it hints 428627f7eb2Smrg@cindex diagnostics guidelines, fix-it hints 429627f7eb2Smrg 430627f7eb2SmrgGCC's diagnostic subsystem can emit @dfn{fix-it hints}: small suggested 431627f7eb2Smrgedits to the user's source code. 432627f7eb2Smrg 433627f7eb2SmrgThey are printed by default underneath the code in question. They 434627f7eb2Smrgcan also be viewed via @option{-fdiagnostics-generate-patch} and 435627f7eb2Smrg@option{-fdiagnostics-parseable-fixits}. With the latter, an IDE 436627f7eb2Smrgought to be able to offer to automatically apply the suggested fix. 437627f7eb2Smrg 438627f7eb2SmrgFix-it hints contain code fragments, and thus they should not be marked 439627f7eb2Smrgfor translation. 440627f7eb2Smrg 441627f7eb2SmrgFix-it hints can be added to a diagnostic by using a @code{rich_location} 442627f7eb2Smrgrather than a @code{location_t} - the fix-it hints are added to the 443627f7eb2Smrg@code{rich_location} using one of the various @code{add_fixit} member 444627f7eb2Smrgfunctions of @code{rich_location}. They are documented with 445627f7eb2Smrg@code{rich_location} in @file{libcpp/line-map.h}. 446627f7eb2SmrgIt's easiest to use the @code{gcc_rich_location} subclass of 447627f7eb2Smrg@code{rich_location} found in @file{gcc-rich-location.h}, as this 448627f7eb2Smrgimplicitly supplies the @code{line_table} variable. 449627f7eb2Smrg 450627f7eb2SmrgFor example: 451627f7eb2Smrg 452627f7eb2Smrg@smallexample 453627f7eb2Smrg if (const char *suggestion = hint.suggestion ()) 454627f7eb2Smrg @{ 455627f7eb2Smrg gcc_rich_location richloc (location); 456627f7eb2Smrg richloc.add_fixit_replace (suggestion); 457627f7eb2Smrg error_at (&richloc, 458627f7eb2Smrg "%qE does not name a type; did you mean %qs?", 459627f7eb2Smrg id, suggestion); 460627f7eb2Smrg @} 461627f7eb2Smrg@end smallexample 462627f7eb2Smrg 463627f7eb2Smrg@noindent 464627f7eb2Smrgwhich can lead to: 465627f7eb2Smrg 466627f7eb2Smrg@smallexample 467627f7eb2Smrgspellcheck-typenames.C:73:1: error: 'singed' does not name a type; did 468627f7eb2Smrg you mean 'signed'? 469627f7eb2Smrg 73 | singed char ch; 470627f7eb2Smrg | ^~~~~~ 471627f7eb2Smrg | signed 472627f7eb2Smrg@end smallexample 473627f7eb2Smrg 474627f7eb2SmrgNon-trivial edits can be built up by adding multiple fix-it hints to one 475627f7eb2Smrg@code{rich_location}. It's best to express the edits in terms of the 476627f7eb2Smrglocations of individual tokens. Various handy functions for adding 477627f7eb2Smrgfix-it hints for idiomatic C and C++ can be seen in 478627f7eb2Smrg@file{gcc-rich-location.h}. 479627f7eb2Smrg 480627f7eb2Smrg@subsubsection Fix-it hints should work 481627f7eb2Smrg 482627f7eb2SmrgWhen implementing a fix-it hint, please verify that the suggested edit 483627f7eb2Smrgleads to fixed, compilable code. (Unfortunately, this currently must be 484627f7eb2Smrgdone by hand using @option{-fdiagnostics-generate-patch}. It would be 485627f7eb2Smrggood to have an automated way of verifying that fix-it hints actually fix 486627f7eb2Smrgthe code). 487627f7eb2Smrg 488627f7eb2SmrgFor example, a ``gotcha'' here is to forget to add a space when adding a 489627f7eb2Smrgmissing reserved word. Consider a C++ fix-it hint that adds 490627f7eb2Smrg@code{typename} in front of a template declaration. A naive way to 491627f7eb2Smrgimplement this might be: 492627f7eb2Smrg 493627f7eb2Smrg@smallexample 494627f7eb2Smrggcc_rich_location richloc (loc); 495627f7eb2Smrg// BAD: insertion is missing a trailing space 496627f7eb2Smrgrichloc.add_fixit_insert_before ("typename"); 497627f7eb2Smrgerror_at (&richloc, "need %<typename%> before %<%T::%E%> because " 498627f7eb2Smrg "%qT is a dependent scope", 499627f7eb2Smrg parser->scope, id, parser->scope); 500627f7eb2Smrg@end smallexample 501627f7eb2Smrg 502627f7eb2Smrg@noindent 503627f7eb2SmrgWhen applied to the code, this might lead to: 504627f7eb2Smrg 505627f7eb2Smrg@smallexample 506627f7eb2SmrgT::type x; 507627f7eb2Smrg@end smallexample 508627f7eb2Smrg 509627f7eb2Smrg@noindent 510627f7eb2Smrgbeing ``corrected'' to: 511627f7eb2Smrg 512627f7eb2Smrg@smallexample 513627f7eb2SmrgtypenameT::type x; 514627f7eb2Smrg@end smallexample 515627f7eb2Smrg 516627f7eb2Smrg@noindent 517627f7eb2SmrgIn this case, the correct thing to do is to add a trailing space after 518627f7eb2Smrg@code{typename}: 519627f7eb2Smrg 520627f7eb2Smrg@smallexample 521627f7eb2Smrggcc_rich_location richloc (loc); 522627f7eb2Smrg// OK: note that here we have a trailing space 523627f7eb2Smrgrichloc.add_fixit_insert_before ("typename "); 524627f7eb2Smrgerror_at (&richloc, "need %<typename%> before %<%T::%E%> because " 525627f7eb2Smrg "%qT is a dependent scope", 526627f7eb2Smrg parser->scope, id, parser->scope); 527627f7eb2Smrg@end smallexample 528627f7eb2Smrg 529627f7eb2Smrg@noindent 530627f7eb2Smrgleading to this corrected code: 531627f7eb2Smrg 532627f7eb2Smrg@smallexample 533627f7eb2Smrgtypename T::type x; 534627f7eb2Smrg@end smallexample 535627f7eb2Smrg 536627f7eb2Smrg@subsubsection Express deletion in terms of deletion, not replacement 537627f7eb2Smrg 538627f7eb2SmrgIt's best to express deletion suggestions in terms of deletion fix-it 539627f7eb2Smrghints, rather than replacement fix-it hints. For example, consider this: 540627f7eb2Smrg 541627f7eb2Smrg@smallexample 542627f7eb2Smrg auto_diagnostic_group d; 543627f7eb2Smrg gcc_rich_location richloc (location_of (retval)); 544627f7eb2Smrg tree name = DECL_NAME (arg); 545627f7eb2Smrg richloc.add_fixit_replace (IDENTIFIER_POINTER (name)); 546627f7eb2Smrg warning_at (&richloc, OPT_Wredundant_move, 547627f7eb2Smrg "redundant move in return statement"); 548627f7eb2Smrg@end smallexample 549627f7eb2Smrg 550627f7eb2Smrg@noindent 551627f7eb2Smrgwhich is intended to e.g.@: replace a @code{std::move} with the underlying 552627f7eb2Smrgvalue: 553627f7eb2Smrg 554627f7eb2Smrg@smallexample 555627f7eb2Smrg return std::move (retval); 556627f7eb2Smrg ~~~~~~~~~~^~~~~~~~ 557627f7eb2Smrg retval 558627f7eb2Smrg@end smallexample 559627f7eb2Smrg 560627f7eb2Smrg@noindent 561627f7eb2Smrgwhere the change has been expressed as replacement, replacing 562627f7eb2Smrgwith the name of the declaration. 563627f7eb2SmrgThis works for simple cases, but consider this case: 564627f7eb2Smrg 565627f7eb2Smrg@smallexample 566627f7eb2Smrg#ifdef SOME_CONFIG_FLAG 567627f7eb2Smrg# define CONFIGURY_GLOBAL global_a 568627f7eb2Smrg#else 569627f7eb2Smrg# define CONFIGURY_GLOBAL global_b 570627f7eb2Smrg#endif 571627f7eb2Smrg 572627f7eb2Smrgint fn () 573627f7eb2Smrg@{ 574627f7eb2Smrg return std::move (CONFIGURY_GLOBAL /* some comment */); 575627f7eb2Smrg@} 576627f7eb2Smrg@end smallexample 577627f7eb2Smrg 578627f7eb2Smrg@noindent 579627f7eb2SmrgThe above implementation erroneously strips out the macro and the 580627f7eb2Smrgcomment in the fix-it hint: 581627f7eb2Smrg 582627f7eb2Smrg@smallexample 583627f7eb2Smrg return std::move (CONFIGURY_GLOBAL /* some comment */); 584627f7eb2Smrg ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 585627f7eb2Smrg global_a 586627f7eb2Smrg@end smallexample 587627f7eb2Smrg 588627f7eb2Smrg@noindent 589627f7eb2Smrgand thus this resulting code: 590627f7eb2Smrg 591627f7eb2Smrg@smallexample 592627f7eb2Smrg return global_a; 593627f7eb2Smrg@end smallexample 594627f7eb2Smrg 595627f7eb2Smrg@noindent 596627f7eb2SmrgIt's better to do deletions in terms of deletions; deleting the 597627f7eb2Smrg@code{std::move (} and the trailing close-paren, leading to 598627f7eb2Smrgthis: 599627f7eb2Smrg 600627f7eb2Smrg@smallexample 601627f7eb2Smrg return std::move (CONFIGURY_GLOBAL /* some comment */); 602627f7eb2Smrg ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 603627f7eb2Smrg CONFIGURY_GLOBAL /* some comment */ 604627f7eb2Smrg@end smallexample 605627f7eb2Smrg 606627f7eb2Smrg@noindent 607627f7eb2Smrgand thus this result: 608627f7eb2Smrg 609627f7eb2Smrg@smallexample 610627f7eb2Smrg return CONFIGURY_GLOBAL /* some comment */; 611627f7eb2Smrg@end smallexample 612627f7eb2Smrg 613627f7eb2Smrg@noindent 614627f7eb2SmrgUnfortunately, the pertinent @code{location_t} values are not always 615627f7eb2Smrgavailable. 616627f7eb2Smrg 617627f7eb2Smrg@c the above was https://gcc.gnu.org/ml/gcc-patches/2018-08/msg01474.html 618627f7eb2Smrg 619627f7eb2Smrg@subsubsection Multiple suggestions 620627f7eb2Smrg 621627f7eb2SmrgIn the rare cases where you need to suggest more than one mutually 622627f7eb2Smrgexclusive solution to a problem, this can be done by emitting 623627f7eb2Smrgmultiple notes and calling 624627f7eb2Smrg@code{rich_location::fixits_cannot_be_auto_applied} on each note's 625627f7eb2Smrg@code{rich_location}. If this is called, then the fix-it hints in 626627f7eb2Smrgthe @code{rich_location} will be printed, but will not be added to 627627f7eb2Smrggenerated patches. 628627f7eb2Smrg 629627f7eb2Smrg 630627f7eb2Smrg@node Guidelines for Options 631627f7eb2Smrg@section Guidelines for Options 632627f7eb2Smrg@cindex command-line options, guidelines for 633627f7eb2Smrg@cindex options, guidelines for 634627f7eb2Smrg@cindex guidelines for options 635627f7eb2Smrg 636627f7eb2Smrg@c TODO 637