Skip to content

Commit b854cf0

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 2236af8 commit b854cf0

16 files changed

Lines changed: 219 additions & 166 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() != StmtKind.Label && !ma.warnings.no_unreachable_code) {
66-
ma.warn(s.getLoc(), "unreachable code");
65+
if (s.getKind() != StmtKind.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 & 18 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,54 +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-
c.diags.warn(a.getLoc(), "unused module '%s'", a.getName());
45+
c.diags.warn(W_unused_module, a.getLoc(), "unused module '%s'", a.getName());
4646
}
4747

4848
fn void Checker.check(void* arg, Decl* d) {
4949
Checker* c = arg;
5050
bool used = d.isUsed();
51-
if (used && d.isPublic() && !d.isUsedPublic() && !c.warnings.no_unused_public && !d.hasAttrUnused()) {
52-
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());
5353
}
5454

55+
WarningKind wk = W_unknown;
5556
switch (d.getKind()) {
5657
case Function:
57-
if (c.warnings.no_unused_function) return;
5858
if (d.hasAttrUnused()) return;
59+
wk = W_unused_function;
5960
break;
6061
case Import:
61-
if (c.warnings.no_unused_import) return;
62+
wk = W_unused_import;
6263
break;
6364
case StructType:
6465
if (used) {
6566
c.checkStructMembers(d);
6667
}
67-
if (c.warnings.no_unused_type) return;
68+
wk = W_unused_type;
6869
break;
6970
case EnumType:
70-
if (used && !c.warnings.no_unused_enum_constant) {
71-
c.checkEnum((EnumTypeDecl*)d);
71+
if (used && c.warnings.test(W_unused_enum_constant)) {
72+
c.checkEnum((EnumTypeDecl*)(d));
7273
}
74+
wk = W_unused_enum_constant;
7375
break;
7476
case EnumConstant:
77+
wk = W_unused_enum_constant;
7578
break;
7679
case FunctionType:
77-
if (c.warnings.no_unused_type) return;
80+
wk = W_unused_type;
7881
break;
7982
case AliasType:
80-
if (c.warnings.no_unused_type) return;
83+
wk = W_unused_type;
8184
break;
8285
case Variable:
83-
if (c.warnings.no_unused_variable) return;
86+
wk = W_unused_variable;
8487
break;
8588
}
8689
if (!used && !d.hasAttrUnused() && !d.isExported()) {
87-
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());
8891
return;
8992
}
9093
}
@@ -96,7 +99,7 @@ fn void Checker.checkEnum(Checker* c, EnumTypeDecl* d) {
9699
EnumConstantDecl* ecd = constants[i];
97100
Decl* dd = (Decl*)ecd;
98101
if (!dd.isUsed()) {
99-
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());
100103
}
101104
}
102105
}
@@ -110,8 +113,8 @@ fn void Checker.checkStructMembers(Checker* c, Decl* d) {
110113
if (member.isStructType()) {
111114
c.checkStructMembers(member);
112115
} else {
113-
if (!member.isUsed() && !c.warnings.no_unused_variable) {
114-
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());
115118
}
116119
}
117120
}

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;
@@ -122,14 +122,13 @@ public fn Target* create(u32 name_idx, SrcLoc loc, Kind kind, string_pool.Pool*
122122
Target* t = stdlib.calloc(1, sizeof(Target));
123123
t.name_idx = name_idx;
124124
t.loc = loc;
125-
// remove this once the bootstrap handles improved flow analysis
126-
t.warnings.no_unreachable_code = true;
127125
t.kind = kind;
128126
t.features.init(pool);
129127
t.libs.init();
130128
t.exports.init(pool);
131129
t.files.init(8);
132130
t.asm_files.init(0);
131+
t.enableWarnings();
133132
return t;
134133
}
135134

@@ -184,43 +183,19 @@ public fn void Target.addLib(Target* t, u32 lib, Kind kind) {
184183
t.libs.add(lib, kind);
185184
}
186185

187-
public fn void Target.disableWarnings(Target* t) {
188-
t.warnings.no_unused = true;
189-
t.warnings.no_unused_variable = true;
190-
t.warnings.no_unused_function = true;
191-
t.warnings.no_unused_parameter = true;
192-
t.warnings.no_unused_type = true;
193-
t.warnings.no_unused_module = true;
194-
t.warnings.no_unused_import = true;
195-
t.warnings.no_unused_public = true;
196-
t.warnings.no_unused_label = true;
197-
t.warnings.no_unused_enum_constant = true;
198-
t.warnings.no_unreachable_code = true;
199-
t.warnings.no_unknown_attribute = true;
200-
t.warnings.no_deprecated = true;
186+
public fn void Target.disableWarnings(Target* t) @(unused) {
187+
t.warnings.clearAll();
201188
}
202189

203190
public fn void Target.enableWarnings(Target* t) {
204-
t.warnings.no_unused = false;
205-
t.warnings.no_unused_variable = false;
206-
t.warnings.no_unused_function = false;
207-
t.warnings.no_unused_parameter = false;
208-
t.warnings.no_unused_type = false;
209-
t.warnings.no_unused_module = false;
210-
t.warnings.no_unused_import = false;
211-
t.warnings.no_unused_public = false;
212-
t.warnings.no_unused_label = false;
213-
t.warnings.no_unused_enum_constant = false;
214-
t.warnings.no_unreachable_code = false;
215-
t.warnings.no_unknown_attribute = false;
216-
t.warnings.no_deprecated = false;
217-
}
218-
219-
public fn const warning_flags.Flags* Target.getWarnings(const Target* t) {
191+
t.warnings.setAll();
192+
}
193+
194+
public fn const WarningFlags* Target.getWarnings(const Target* t) {
220195
return &t.warnings;
221196
}
222197

223-
public fn warning_flags.Flags* Target.getWarnings2(Target* t) {
198+
public fn WarningFlags* Target.getWarnings2(Target* t) {
224199
return &t.warnings;
225200
}
226201

0 commit comments

Comments
 (0)