Skip to content

Commit e9d9457

Browse files
committed
compiler: more flexible warning system
* add `WarningKind` enumeration and simplify `Flags` structure * rename `warning_flags.Flags` as `WarningFlags` * remove temporary unreachable code hack * all targets have all warnings enabled by default * extend `WarningFlags` type with type functions * simplify `Target.enableWarnings()` and `Target.disableWarnings()` * add warnings for `const-return-type` and `idiomatic-parentheses` * accept both '$warnings unused' and '$warnings no-unused' etc.
1 parent 890f3a4 commit e9d9457

16 files changed

Lines changed: 218 additions & 167 deletions

analyser/module_analyser.c2

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import name_vector local;
2929
import src_loc local;
3030
import scope;
3131
import string_pool;
32-
import warning_flags;
32+
import warning_flags local;
3333
import struct_func_list as sf_list;
3434
import incr_array_list as ia_list;
3535

@@ -48,7 +48,7 @@ public type Analyser struct @(opaque) {
4848
string_pool.Pool* astPool;
4949
ast_builder.Builder* builder;
5050
module_list.List* allmodules;
51-
const warning_flags.Flags* warnings;
51+
const WarningFlags* warnings;
5252

5353
// variables below differs per run
5454
Module* mod;
@@ -84,7 +84,7 @@ public fn Analyser* create(diagnostics.Diags* diags,
8484
string_pool.Pool* astPool,
8585
ast_builder.Builder* builder,
8686
module_list.List* allmodules,
87-
const warning_flags.Flags* warnings)
87+
const WarningFlags* warnings)
8888
{
8989
Analyser* ma = stdlib.calloc(1, sizeof(Analyser));
9090
ma.diags = diags;
@@ -296,10 +296,10 @@ fn void Analyser.note(Analyser* ma, SrcLoc loc, const char* format @(printf_form
296296
va_end(args);
297297
}
298298

299-
fn void Analyser.warn(Analyser* ma, SrcLoc loc, const char* format @(printf_format), ...) {
299+
fn void Analyser.warn(Analyser* ma, WarningKind wk, SrcLoc loc, const char* format @(printf_format), ...) {
300300
va_list args;
301301
va_start(args, format);
302-
ma.diags.warn2(loc, format, args);
302+
ma.diags.warn2(wk, loc, format, args);
303303
va_end(args);
304304
}
305305

@@ -330,7 +330,7 @@ fn void Analyser.createGlobalScope(void* arg, AST* a) {
330330
a.getImports(),
331331
ma.mod,
332332
ma.mod.getSymbols(),
333-
!ma.warnings.no_unused_variable);
333+
ma.warnings.test(W_unused_variable));
334334
a.setPtr(s);
335335
}
336336

analyser/module_analyser_call.c2

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,11 @@ fn QualType Analyser.analyseCallExpr(Analyser* ma, Expr** e_ptr) {
7373
}
7474
}
7575

76-
if (fd.hasAttrDeprecated() && !ma.warnings.no_deprecated) {
76+
if (fd.hasAttrDeprecated() && ma.warnings.test(W_deprecated)) {
7777
const AST* a = ((Decl*)fd).getAST();
7878
const Attr* deprecated = a.getAttr(((Decl*)fd), Deprecated);
7979
const char* msg = ma.astPool.idx2str(deprecated.value.text);
80-
ma.warn(origFn.getLoc(), "function %s is deprecated: %s", fd.asDecl().getFullName(), msg);
80+
ma.warn(W_deprecated, origFn.getLoc(), "function %s is deprecated: %s", fd.asDecl().getFullName(), msg);
8181
//return QualType_Invalid;
8282
}
8383

@@ -663,7 +663,7 @@ fn FunctionDecl* Analyser.instantiateTemplateFunction(Analyser* ma, CallExpr* ca
663663
d.getAST().getImports(),
664664
template_mod,
665665
template_mod.getSymbols(),
666-
!ma.warnings.no_unused_variable);
666+
ma.warnings.test(W_unused_variable));
667667
analyser.analyseFunctionBody(instance, tmpScope);
668668
tmpScope.free();
669669
analyser.free();

analyser/module_analyser_function.c2

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ fn void Analyser.analyseFunction(Analyser* ma, FunctionDecl* fd) {
5555
}
5656

5757
if (canon.isConst() && !canon.isPointer()) {
58-
ma.warn(rtype.getLoc(), "'const' type qualifier on return type has no effect");
58+
ma.warn(W_const_return_type, rtype.getLoc(), "'const' type qualifier on return type has no effect");
5959
}
6060

6161
bool is_public = fd.asDecl().isPublic();
@@ -256,12 +256,12 @@ fn void Analyser.analyseFunctionBody(Analyser* ma, FunctionDecl* fd, scope.Scope
256256
}
257257
}
258258

259-
if (!ma.warnings.no_unused_parameter && !fd.hasAttrUnusedParams()) {
259+
if (ma.warnings.test(W_unused_parameter) && !fd.hasAttrUnusedParams()) {
260260
for (u32 i=0; i<num_params; i++) {
261261
Decl* p = (Decl*)params[i];
262262
if (!p.isUsed() && p.getNameIdx()) {
263263
// TODO check attribute?
264-
ma.warn(p.getLoc(), "unused parameter '%s'", p.getName());
264+
ma.warn(W_unused_parameter, p.getLoc(), "unused parameter '%s'", p.getName());
265265
}
266266
}
267267
}
@@ -273,8 +273,8 @@ fn void Analyser.analyseFunctionBody(Analyser* ma, FunctionDecl* fd, scope.Scope
273273
for (u32 i=0; i<num_labels; i++) {
274274
const Label* l = &labels[i];
275275
if (l.is_label) {
276-
if (!l.used && !ma.warnings.no_unused_label) {
277-
ma.warn(l.loc, "unused label '%s'", ast.idx2name(l.name_idx));
276+
if (!l.used) {
277+
ma.warn(W_unused_label, l.loc, "unused label '%s'", ast.idx2name(l.name_idx));
278278
}
279279
} else {
280280
ma.error(l.loc, "use of undeclared label '%s'", ast.idx2name(l.name_idx));

analyser/module_analyser_stmt.c2

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ fn bool Analyser.isNoReturn(Analyser* ma, Expr* e) {
6262
fn FlowBits Analyser.analyseStmt(Analyser* ma, Stmt* s, bool checkEffect) {
6363
FlowBits flow = 0;
6464
if (ma.scope.isUnreachable()) {
65-
if (s.getKind() != Label && !ma.warnings.no_unreachable_code) {
66-
ma.warn(s.getLoc(), "unreachable code");
65+
if (s.getKind() != Label) {
66+
ma.warn(W_unreachable_code, s.getLoc(), "unreachable code");
6767
}
6868
ma.scope.setReachable(); // prevent multiple warnings
6969
}
@@ -219,7 +219,7 @@ fn QualType Analyser.analyseCondition(Analyser* ma, Stmt** s_ptr, bool check_ass
219219
e = (Expr*)*s_ptr; // re-read in case of ImplicitCast insertions
220220

221221
if (check_assign && e.isAssignment()) {
222-
ma.warn(e.getLoc(), "using the result of an assignment as a condition without parentheses");
222+
ma.warn(W_idiomatic_parentheses, e.getLoc(), "using the result of an assignment as a condition without parentheses");
223223
}
224224

225225
return qt;

analyser/scope.c2

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import diagnostics;
2020
import module_list;
2121
import constants;
2222
import src_loc local;
23+
//import warning_flags local;
2324

2425
import stdlib;
2526
import string;
@@ -163,7 +164,7 @@ public fn void Scope.exit(Scope* s, bool has_error) {
163164
if (!d.isUsed()) {
164165
ast.VarDecl* vd = (ast.VarDecl*)d;
165166
// Note: params are handled by function
166-
if (vd.isLocal()) s.diags.warn(d.getLoc(), "unused variable '%s'", d.getName());
167+
if (vd.isLocal()) s.diags.warn(W_unused_variable, d.getLoc(), "unused variable '%s'", d.getName());
167168
}
168169
}
169170
}

analyser/unused_checker.c2

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515

1616
module unused_checker;
1717

18-
import warning_flags;
1918
import ast local;
2019
import diagnostics;
20+
import warning_flags local;
2121

2222
public fn void check(diagnostics.Diags* diags,
23-
const warning_flags.Flags* warnings,
23+
const WarningFlags* warnings,
2424
Module* mod)
2525
{
2626
Checker c = {
@@ -37,56 +37,57 @@ public fn void check(diagnostics.Diags* diags,
3737

3838
type Checker struct {
3939
diagnostics.Diags* diags;
40-
const warning_flags.Flags* warnings;
40+
const WarningFlags* warnings;
4141
}
4242

4343
fn void Checker.unused_module(void* arg, AST* a) {
4444
Checker* c = arg;
45-
if (!c.warnings.no_unused_module) {
46-
c.diags.warn(a.getLoc(), "unused module '%s'", a.getName());
47-
}
45+
c.diags.warn(W_unused_module, a.getLoc(), "unused module '%s'", a.getName());
4846
}
4947

5048
fn void Checker.check(void* arg, Decl* d) {
5149
Checker* c = arg;
5250
bool used = d.isUsed();
53-
if (used && d.isPublic() && !d.isUsedPublic() && !c.warnings.no_unused_public && !d.hasAttrUnused()) {
54-
c.diags.warn(d.getLoc(), "%s '%s' is not used public", d.getKindName(), d.getFullName());
51+
if (used && d.isPublic() && !d.isUsedPublic() && !d.hasAttrUnused()) {
52+
c.diags.warn(W_unused_public, d.getLoc(), "%s '%s' is not used public", d.getKindName(), d.getFullName());
5553
}
5654

55+
WarningKind wk = W_unknown;
5756
switch (d.getKind()) {
5857
case Function:
59-
if (c.warnings.no_unused_function) return;
6058
if (d.hasAttrUnused()) return;
59+
wk = W_unused_function;
6160
break;
6261
case Import:
63-
if (c.warnings.no_unused_import) return;
62+
wk = W_unused_import;
6463
break;
6564
case StructType:
6665
if (used) {
6766
c.checkStructMembers(d);
6867
}
69-
if (c.warnings.no_unused_type) return;
68+
wk = W_unused_type;
7069
break;
7170
case EnumType:
72-
if (used && !c.warnings.no_unused_enum_constant) {
73-
c.checkEnum((EnumTypeDecl*)d);
71+
if (used && c.warnings.test(W_unused_enum_constant)) {
72+
c.checkEnum((EnumTypeDecl*)(d));
7473
}
74+
wk = W_unused_enum_constant;
7575
break;
7676
case EnumConstant:
77+
wk = W_unused_enum_constant;
7778
break;
7879
case FunctionType:
79-
if (c.warnings.no_unused_type) return;
80+
wk = W_unused_type;
8081
break;
8182
case AliasType:
82-
if (c.warnings.no_unused_type) return;
83+
wk = W_unused_type;
8384
break;
8485
case Variable:
85-
if (c.warnings.no_unused_variable) return;
86+
wk = W_unused_variable;
8687
break;
8788
}
8889
if (!used && !d.hasAttrUnused() && !d.isExported()) {
89-
c.diags.warn(d.getLoc(), "unused %s '%s'", d.getKindName(), d.getFullName());
90+
c.diags.warn(wk, d.getLoc(), "unused %s '%s'", d.getKindName(), d.getFullName());
9091
return;
9192
}
9293
}
@@ -98,7 +99,7 @@ fn void Checker.checkEnum(Checker* c, EnumTypeDecl* d) {
9899
EnumConstantDecl* ecd = constants[i];
99100
Decl* dd = (Decl*)ecd;
100101
if (!dd.isUsed()) {
101-
c.diags.warn(dd.getLoc(), "unused %s '%s'", dd.getKindName(), dd.getName());
102+
c.diags.warn(W_unused_enum_constant, dd.getLoc(), "unused %s '%s'", dd.getKindName(), dd.getName());
102103
}
103104
}
104105
}
@@ -112,8 +113,8 @@ fn void Checker.checkStructMembers(Checker* c, Decl* d) {
112113
if (member.isStructType()) {
113114
c.checkStructMembers(member);
114115
} else {
115-
if (!member.isUsed() && !c.warnings.no_unused_variable) {
116-
c.diags.warn(member.getLoc(), "unused %s member '%s'", std.isStruct() ? "struct" : "union", member.getName());
116+
if (!member.isUsed()) {
117+
c.diags.warn(W_unused_variable, member.getLoc(), "unused %s member '%s'", std.isStruct() ? "struct" : "union", member.getName());
117118
}
118119
}
119120
}

common/attr_handler.c2

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ module attr_handler;
1818
import ast;
1919
import attr local;
2020
import diagnostics;
21-
import warning_flags;
21+
import warning_flags local;
2222

2323
import stdlib;
2424
import string;
@@ -31,15 +31,15 @@ type Entry struct {
3131

3232
public type Handler struct @(opaque) {
3333
diagnostics.Diags* diags; // no ownership
34-
const warning_flags.Flags* warnings;
34+
const WarningFlags* warnings;
3535

3636
Entry* entries;
3737
u32 count;
3838
u32 capacity;
3939
}
4040

4141
public fn Handler* create(diagnostics.Diags* diags,
42-
const warning_flags.Flags* warnings) {
42+
const WarningFlags* warnings) {
4343
Handler* h = stdlib.calloc(1, sizeof(Handler));
4444
h.diags = diags;
4545
h.warnings = warnings;
@@ -77,9 +77,7 @@ public fn bool Handler.handle(Handler* h, ast.Decl* d, const Attr* a) {
7777
Entry* e = &h.entries[i];
7878
if (e.name == a.name) return e.func(e.arg, d, a);
7979
}
80-
if (!h.warnings.no_unknown_attribute) {
81-
h.diags.warn(a.loc, "unknown attribute '%s'", ast.idx2name(a.name));
82-
}
80+
h.diags.warn(W_unknown_attribute, a.loc, "unknown attribute '%s'", ast.idx2name(a.name));
8381
return false;
8482
}
8583

common/build_target.c2

Lines changed: 10 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import file_list local;
1919
import src_loc local;
2020
import string_list;
2121
import string_pool;
22-
import warning_flags;
22+
import warning_flags local;
2323

2424
import stdlib;
2525
import string;
@@ -100,7 +100,7 @@ public fn void PluginList.add(PluginList* l, u32 name, u32 options, SrcLoc loc)
100100
public type Target struct @(opaque) {
101101
u32 name_idx; // index into auxPool
102102
SrcLoc loc;
103-
warning_flags.Flags warnings;
103+
WarningFlags warnings;
104104
Kind kind;
105105

106106
bool disable_asserts;
@@ -123,14 +123,13 @@ public fn Target* create(u32 name_idx, SrcLoc loc, Kind kind, string_pool.Pool*
123123
Target* t = stdlib.calloc(1, sizeof(Target));
124124
t.name_idx = name_idx;
125125
t.loc = loc;
126-
// remove this once the bootstrap handles improved flow analysis
127-
t.warnings.no_unreachable_code = true;
128126
t.kind = kind;
129127
t.features.init(pool);
130128
t.libs.init();
131129
t.exports.init(pool);
132130
t.files.init(8);
133131
t.asm_files.init(0);
132+
t.enableWarnings();
134133
return t;
135134
}
136135

@@ -189,43 +188,19 @@ public fn void Target.addLib(Target* t, u32 lib, Kind kind) {
189188
t.libs.add(lib, kind);
190189
}
191190

192-
public fn void Target.disableWarnings(Target* t) {
193-
t.warnings.no_unused = true;
194-
t.warnings.no_unused_variable = true;
195-
t.warnings.no_unused_function = true;
196-
t.warnings.no_unused_parameter = true;
197-
t.warnings.no_unused_type = true;
198-
t.warnings.no_unused_module = true;
199-
t.warnings.no_unused_import = true;
200-
t.warnings.no_unused_public = true;
201-
t.warnings.no_unused_label = true;
202-
t.warnings.no_unused_enum_constant = true;
203-
t.warnings.no_unreachable_code = true;
204-
t.warnings.no_unknown_attribute = true;
205-
t.warnings.no_deprecated = true;
191+
public fn void Target.disableWarnings(Target* t) @(unused) {
192+
t.warnings.clearAll();
206193
}
207194

208195
public fn void Target.enableWarnings(Target* t) {
209-
t.warnings.no_unused = false;
210-
t.warnings.no_unused_variable = false;
211-
t.warnings.no_unused_function = false;
212-
t.warnings.no_unused_parameter = false;
213-
t.warnings.no_unused_type = false;
214-
t.warnings.no_unused_module = false;
215-
t.warnings.no_unused_import = false;
216-
t.warnings.no_unused_public = false;
217-
t.warnings.no_unused_label = false;
218-
t.warnings.no_unused_enum_constant = false;
219-
t.warnings.no_unreachable_code = false;
220-
t.warnings.no_unknown_attribute = false;
221-
t.warnings.no_deprecated = false;
222-
}
223-
224-
public fn const warning_flags.Flags* Target.getWarnings(const Target* t) {
196+
t.warnings.setAll();
197+
}
198+
199+
public fn const WarningFlags* Target.getWarnings(const Target* t) {
225200
return &t.warnings;
226201
}
227202

228-
public fn warning_flags.Flags* Target.getWarnings2(Target* t) {
203+
public fn WarningFlags* Target.getWarnings2(Target* t) {
229204
return &t.warnings;
230205
}
231206

0 commit comments

Comments
 (0)