Skip to content

Commit c2caa1c

Browse files
committed
Generate expressive diagnostic messages
1 parent 9aaeadc commit c2caa1c

File tree

6 files changed

+100
-0
lines changed

6 files changed

+100
-0
lines changed

changelog/error-pretty.dd

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
dmd now supports expressive diagnostic error messages with `-verrors=pretty`
2+
3+
With the new CLI option `-verrors=pretty` dmd will now show the offending line directly in its error messages.
4+
Consider this faulty program `test.d`:
5+
6+
---
7+
void foo()
8+
{
9+
10+
a = 1;
11+
}
12+
---
13+
14+
Now run it with `-verrors=pretty`:
15+
16+
$(CONSOLE
17+
> dmd -verrors=pretty test.d
18+
ee.d(5): $(RED Error): undefined identifier a
19+
a = 1;
20+
^
21+
)

src/dmd/cli.d

+3
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,9 @@ dmd -cov -unittest myprog.d
553553
Option("verrors=spec",
554554
"show errors from speculative compiles such as __traits(compiles,...)"
555555
),
556+
Option("verrors=pretty",
557+
"Pretty-print error messages with annotation of the erroring source line"
558+
),
556559
Option("-version",
557560
"print compiler version and exit"
558561
),

src/dmd/errors.d

+35
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,41 @@ private void verrorPrint(const ref Loc loc, Color headerColor, const(char)* head
236236
else
237237
fputs(tmp.peekString(), stderr);
238238
fputc('\n', stderr);
239+
240+
if (global.params.prettyPrintErrors &&
241+
// ignore mixins for now
242+
!loc.filename.strstr(".d-mixin-"))
243+
{
244+
auto fp = fopen(loc.filename, "r");
245+
scope(exit) fclose(fp);
246+
247+
if (fp)
248+
{
249+
char* lineptr;
250+
import core.sys.posix.stdio : getline;
251+
static if (__traits(compiles, {ulong n2; getline(&lineptr, &n2, fp);}))
252+
ulong n = 1024;
253+
else
254+
uint n = 1024;
255+
foreach (_; 0 .. loc.linnum)
256+
{
257+
assert(getline(&lineptr, &n, fp) > 0);
258+
if (lineptr is null)
259+
goto end;
260+
}
261+
if (lineptr is null)
262+
goto end;
263+
fprintf(stderr, "%s", lineptr);
264+
265+
if (loc.charnum >= 1)
266+
foreach (_; 1 .. loc.charnum)
267+
fputc(' ', stderr);
268+
269+
fputc('^', stderr);
270+
}
271+
fputc('\n', stderr);
272+
}
273+
end:
239274
fflush(stderr); // ensure it gets written out in case of compiler aborts
240275
}
241276

src/dmd/globals.d

+1
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ struct Param
158158
*/
159159

160160
bool showGaggedErrors; // print gagged errors anyway
161+
bool prettyPrintErrors; // pretty print errors with the actual line
161162
bool manual; // open browser on compiler manual
162163
bool usage; // print usage and exit
163164
bool mcpuUsage; // print help on -mcpu switch

src/dmd/mars.d

+4
Original file line numberDiff line numberDiff line change
@@ -1732,6 +1732,10 @@ private bool parseCommandLine(const ref Strings arguments, const size_t argc, re
17321732
{
17331733
params.showGaggedErrors = true;
17341734
}
1735+
else if (startsWith(p + 9, "pretty"))
1736+
{
1737+
params.prettyPrintErrors = true;
1738+
}
17351739
else
17361740
goto Lerror;
17371741
}
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
REQUIRED_ARGS: -verrors=pretty
3+
TEST_OUTPUT:
4+
---
5+
fail_compilation/fail_pretty_errors.d(20): Error: undefined identifier `a`
6+
a = 1;
7+
^
8+
fail_compilation/fail_pretty_errors.d-mixin-25(25): Error: undefined identifier `b`
9+
fail_compilation/fail_pretty_errors.d(30): Error: cannot implicitly convert expression `5` of type `int` to `string`
10+
string x = 5;
11+
^
12+
fail_compilation/fail_pretty_errors.d(35): Error: mixin `fail_pretty_errors.testMixin2.mixinTemplate!()` error instantiating
13+
mixin mixinTemplate;
14+
^
15+
---
16+
*/
17+
18+
void foo()
19+
{
20+
a = 1;
21+
}
22+
23+
void testMixin1()
24+
{
25+
mixin("b = 1;");
26+
}
27+
28+
mixin template mixinTemplate()
29+
{
30+
string x = 5;
31+
}
32+
33+
void testMixin2()
34+
{
35+
mixin mixinTemplate;
36+
}

0 commit comments

Comments
 (0)