Skip to content

Commit 7c6c0eb

Browse files
committed
default param: move check to analyseFunction to prevent follow-up errors
* prevent follow-up errors in calls to function where analyse-proto fails * added test for 'callback' parameters * added test for public/non-public use
1 parent 8ed61ed commit 7c6c0eb

10 files changed

+70
-46
lines changed

analyser/module_analyser.c2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,7 @@ fn void Analyser.analyseGlobalVarDecl(Analyser* ma, VarDecl* v) {
621621
ma.checkStack[ma.checkIndex-1].usedPublic = false;
622622
ma.usedPublic = false;
623623
}
624-
ma.analyseInitExpr(v.getInit2(), res, v.getAssignLoc(), false);
624+
ma.analyseInitExpr(v.getInit2(), res, v.getAssignLoc(), false, false);
625625
} else {
626626
if (res.isConstant() && !embed) {
627627
ma.error(d.getLoc(), "constant variable '%s' must be initialized", d.getFullName());

analyser/module_analyser_binop.c2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,7 @@ fn QualType Analyser.analyseBinaryOperator(Analyser* ma, Expr** e_ptr) {
574574
return builtins[BuiltinKind.Bool];
575575
}
576576
if (opcode == BinaryOpcode.Assign) {
577-
if (!ma.analyseInitExpr(b.getRHS2(), ltype, e.getLoc(), false))
577+
if (!ma.analyseInitExpr(b.getRHS2(), ltype, e.getLoc(), false, false))
578578
return QualType_Invalid;
579579
rtype = b.getRHS().getType();
580580
} else {

analyser/module_analyser_call.c2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ fn QualType Analyser.analyseCallExpr(Analyser* ma, Expr** e_ptr) {
168168
continue;
169169
}
170170

171-
if (!ma.analyseInitExpr(&call_args[call_arg_index], vd.asDecl().getType(), call_args[call_arg_index].getLoc(), false))
171+
if (!ma.analyseInitExpr(&call_args[call_arg_index], vd.asDecl().getType(), call_args[call_arg_index].getLoc(), false, false))
172172
return QualType_Invalid;
173173

174174
if (vd.hasPrintfFormat()) {

analyser/module_analyser_function.c2

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,10 @@ fn void Analyser.analyseFunction(Analyser* ma, FunctionDecl* fd) {
6868
VarDecl** params = fd.getParams();
6969
u32 auto_arg_count = 0;
7070
u32 first_auto_arg = 0;
71+
bool has_default = false;
7172
for (u32 i=0; i<num_params; i++) {
72-
VarDecl* v = params[i];
73-
TypeRef* ref = v.getTypeRef();
73+
VarDecl* vd = params[i];
74+
TypeRef* ref = vd.getTypeRef();
7475

7576
QualType res = ma.analyseTypeRef(ref);
7677
if (res.isInvalid()) continue;
@@ -88,31 +89,48 @@ fn void Analyser.analyseFunction(Analyser* ma, FunctionDecl* fd) {
8889

8990
if (is_public) setTypePublicUsed(res);
9091

91-
if (v.hasAutoAttr()) {
92+
if (vd.hasInit()) {
93+
has_default = true;
94+
if (vd.hasAutoAttr()) {
95+
ma.error(vd.getAssignLoc(), "automatic argument cannot have default value");
96+
}
97+
if (vd.hasPrintfFormat()) {
98+
ma.error(vd.getAssignLoc(), "printf_format parameter cannot have default value");
99+
}
100+
Expr** initExpr = vd.getInit2();
101+
ma.analyseInitExpr(initExpr, res, vd.getAssignLoc(), false, true);
102+
} else {
103+
if (has_default) {
104+
Decl* d = (Decl*)vd;
105+
ma.error(d.getLoc(), "parameter must have a default value");
106+
}
107+
}
108+
109+
if (vd.hasAutoAttr()) {
92110
if (auto_arg_count == 0) first_auto_arg = i;
93111
auto_arg_count++;
94112
if (auto_arg_count > 3) {
95113
ma.error(ref.getLoc(), "too many automatic arguments");
96114
}
97115
// check type
98-
if (v.hasAttrAutoFile() && !ref.isConstCharPtr()) { // check for 'const char *'
116+
if (vd.hasAttrAutoFile() && !ref.isConstCharPtr()) { // check for 'const char *'
99117
ma.error(ref.getLoc(), "attribute 'auto_file' requires a parameter of type 'const char*'");
100118
}
101-
if (v.hasAttrAutoLine() && !ref.isU32()) { // check for 'u32'
119+
if (vd.hasAttrAutoLine() && !ref.isU32()) { // check for 'u32'
102120
ma.error(ref.getLoc(), "attribute 'auto_line' requires a parameter of type 'u32'");
103121
}
104-
if (v.hasAttrAutoFunc() && !ref.isConstCharPtr()) { // check for 'const char *'
122+
if (vd.hasAttrAutoFunc() && !ref.isConstCharPtr()) { // check for 'const char *'
105123
ma.error(ref.getLoc(), "attribute 'auto_func' requires a parameter of type 'const char*'");
106124
}
107125
}
108126

109-
if (v.hasPrintfFormat()) {
110-
ma.checkPrintfFormat(v, res, i, fd);
127+
if (vd.hasPrintfFormat()) {
128+
ma.checkPrintfFormat(vd, res, i, fd);
111129
fd.setAttrPrintf((u8)i + 1); // change to 1-based
112130
}
113131

114132
// Note: we dont check the arg name for clash here, but when checking body
115-
Decl* d = (Decl*)v;
133+
Decl* d = (Decl*)vd;
116134
d.setType(res);
117135
d.setChecked();
118136
}
@@ -213,7 +231,6 @@ fn void Analyser.analyseFunctionBody(Analyser* ma, FunctionDecl* fd, scope.Scope
213231

214232
ma.scope.reset();
215233
ma.scope.enter(scope.Function | scope.Decl);
216-
bool has_default = false;
217234
u32 num_params = fd.getNumParams();
218235
VarDecl** params = fd.getParams();
219236
for (u32 i=0; i<num_params; i++) {
@@ -222,27 +239,6 @@ fn void Analyser.analyseFunctionBody(Analyser* ma, FunctionDecl* fd, scope.Scope
222239
bool error = ma.scope.add(p);
223240
if (error) return; // no need to set ma.has_error. NOTE: pushCheck remains!
224241
}
225-
VarDecl* vd = (VarDecl*)p;
226-
if (vd.hasInit()) {
227-
has_default = true;
228-
if (vd.hasAutoAttr()) {
229-
ma.error(vd.getAssignLoc(), "automatic argument cannot have default value");
230-
}
231-
if (vd.hasPrintfFormat()) {
232-
ma.error(vd.getAssignLoc(), "printf_format parameter cannot have default value");
233-
}
234-
Expr** initExpr = vd.getInit2();
235-
if (ma.analyseInitExpr(initExpr, p.getType(), vd.getAssignLoc(), false)) {
236-
Expr* e = vd.getInit();
237-
if (!e.isCtc() && !e.isCtv()) {
238-
ma.errorRange(e.getLoc(), e.getRange(), "default parameter value is not a compile-time value");
239-
}
240-
}
241-
} else {
242-
if (has_default) {
243-
ma.error(p.getLoc(), "parameter must have a default value");
244-
}
245-
}
246242
}
247243

248244
ma.has_error = false;

analyser/module_analyser_init.c2

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import ctv_analyser;
2020
import init_checker;
2121
import src_loc local;
2222

23-
fn bool Analyser.analyseInitExpr(Analyser* ma, Expr** e_ptr, QualType expectedType, SrcLoc assignLoc, bool is_bitfield) {
23+
fn bool Analyser.analyseInitExpr(Analyser* ma, Expr** e_ptr, QualType expectedType, SrcLoc assignLoc, bool is_bitfield, bool is_default_param) {
2424
Expr* e = *e_ptr;
2525

2626
if (!is_bitfield) {
@@ -104,7 +104,11 @@ fn bool Analyser.analyseInitExpr(Analyser* ma, Expr** e_ptr, QualType expectedTy
104104

105105
if (!ma.curFunction && !e.isCtv()) {
106106
if (!e.isCtc()) {
107-
ma.errorRange(e.getLoc(), e.getRange(), "initializer element is not a compile-time constant");
107+
if (is_default_param) {
108+
ma.errorRange(e.getLoc(), e.getRange(), "default parameter value is not a compile-time value");
109+
} else {
110+
ma.errorRange(e.getLoc(), e.getRange(), "initializer element is not a compile-time constant");
111+
}
108112
return false;
109113
}
110114

@@ -172,7 +176,7 @@ fn bool Analyser.analyseArrayDesignatedInit(Analyser* ma, Expr* e, QualType expe
172176
if (val.isInitList()) {
173177
return ma.analyseInitListExpr((InitListExpr*)val, expectedType);
174178
}
175-
bool ok = ma.analyseInitExpr(ad.getInit2(), expectedType, val.getLoc(), false);
179+
bool ok = ma.analyseInitExpr(ad.getInit2(), expectedType, val.getLoc(), false, false);
176180
if (!ok) return false;
177181

178182
if (!ma.curFunction) {
@@ -221,7 +225,7 @@ fn bool Analyser.analyseInitListArray(Analyser* ma, InitListExpr* ile, QualType
221225
have_designators = true;
222226
continue;
223227
}
224-
ok &= ma.analyseInitExpr(&values[i], et, values[i].getLoc(), false);
228+
ok &= ma.analyseInitExpr(&values[i], et, values[i].getLoc(), false, false);
225229
ctc &= values[i].isCtc();
226230
}
227231
current_index = numValues; // TODO also keep track of ArrayDesignatedInit
@@ -409,7 +413,7 @@ fn bool Analyser.analyseStructFieldInit(Analyser* ma, StructTypeDecl* std, InitL
409413
goto out;
410414
}
411415

412-
bool ok = ma.analyseInitExpr(fdi.getInit2(), member.getType(), fdi.getInit().getLoc(), fif.is_bitfield);
416+
bool ok = ma.analyseInitExpr(fdi.getInit2(), member.getType(), fdi.getInit().getLoc(), fif.is_bitfield, false);
413417
if (!ok) goto out;
414418

415419
Expr* inner = fdi.getInit();
@@ -485,7 +489,7 @@ fn bool Analyser.analyseInitListStruct(Analyser* ma, InitListExpr* ile, QualType
485489
}
486490
members[member_idx].setUsed();
487491

488-
bool ok = ma.analyseInitExpr(&values[i], members[member_idx].getType(), values[i].getLoc(), ml.is_bitfield);
492+
bool ok = ma.analyseInitExpr(&values[i], members[member_idx].getType(), values[i].getLoc(), ml.is_bitfield, false);
489493
if (!ok) return false;
490494

491495
if (ml.is_bitfield && value.isCtv()) {

analyser/module_analyser_stmt.c2

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ fn QualType Analyser.analyseDecl(Analyser* ma, VarDecl* vd) {
324324
Expr** initExpr = vd.getInit2();
325325
bool has_init_call = vd.hasInitCall();
326326
if (!has_init_call && initExpr) {
327-
ma.analyseInitExpr(initExpr, res, vd.getAssignLoc(), false);
327+
ma.analyseInitExpr(initExpr, res, vd.getAssignLoc(), false, false);
328328
if (vd.hasLocalQualifier()) {
329329
Expr* e = vd.getInit();
330330
if (!e.isCtc()) {
@@ -411,7 +411,7 @@ fn void Analyser.analyseReturnStmt(Analyser* ma, Stmt* s) {
411411
}
412412
}
413413
if (arg) {
414-
if (!ma.analyseInitExpr(arg, ma.curFunction.getRType(), (*arg).getLoc(), false))
414+
if (!ma.analyseInitExpr(arg, ma.curFunction.getRType(), (*arg).getLoc(), false, false))
415415
return;
416416
QualType qt = (*arg).getType();
417417

test/functions/default_arguments_bad.c2

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@ const char* str = "dummy string";
66
fn void foo1(const char* msg = str) { // @error{default parameter value is not a compile-time value}
77
}
88

9-
fn void foo2(u32 val = val) { // @error{default parameter value is not a compile-time value}
10-
}
11-
129
fn void foo3(u32 val = "default") { // @error{invalid type conversion from 'const char[8]' to 'u32'}
1310
}
1411

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// @warnings{no-unused}
2+
module test;
3+
4+
type Callback fn void (i32 a, i32 b);
5+
6+
fn void test1(Callback cb = nil) { }
7+
8+
fn void test2(Callback cb = my_callback1) { }
9+
10+
fn void test3(Callback cb = my_callback2) { } // @error{invalid function conversion from 'void (i32)' to 'Callback'}
11+
12+
fn void test4(Callback cb = my_callback3) { } // @error{invalid function conversion from 'void (i32, i32, i32)' to 'Callback'}
13+
14+
fn void my_callback1(i32 a, i32 b) {}
15+
16+
fn void my_callback2(i32 a) {}
17+
18+
fn void my_callback3(i32 a, i32 b, i32 c = 3) {}
19+
20+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// @warnings{no-unused}
2+
module test;
3+
4+
public fn void test1(i32 a = Max) {} // @error{public declaration using non-public constant 'test.Max'}
5+
6+
const i32 Max = 10;
7+

test/vars/init_self_arg.c2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// @warnings{no-unused-parameter no-unused-function}
22
module test;
33

4-
fn void test1(i32 d = d) {} // @error{default parameter value is not a compile-time value}
4+
fn void test1(i32 d = d) {} // @error{use of undeclared identifier 'd'}
55

0 commit comments

Comments
 (0)