mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
- Fixes to @format checking #2199.
This commit is contained in:
@@ -28,6 +28,7 @@
|
|||||||
- `--lsp` sometimes does not emit end tag #2194.
|
- `--lsp` sometimes does not emit end tag #2194.
|
||||||
- Improve Android termux detection.
|
- Improve Android termux detection.
|
||||||
- Update Android ABI.
|
- Update Android ABI.
|
||||||
|
- Fixes to `@format` checking #2199.
|
||||||
|
|
||||||
### Stdlib changes
|
### Stdlib changes
|
||||||
- Deprecate `String.is_zstr` and `String.quick_zstr` #2188.
|
- Deprecate `String.is_zstr` and `String.quick_zstr` #2188.
|
||||||
|
|||||||
@@ -1910,80 +1910,138 @@ CHECK_FORMAT:;
|
|||||||
if (data[i] != '%') continue;
|
if (data[i] != '%') continue;
|
||||||
i++;
|
i++;
|
||||||
char c = data[i];
|
char c = data[i];
|
||||||
if (c == '%') continue;
|
NEXT_FLAG:
|
||||||
if (idx == vacount)
|
switch (c)
|
||||||
{
|
{
|
||||||
RETURN_SEMA_FUNC_ERROR(callee->definition, call, "Too few arguments provided for the formatting string.");
|
case '-':
|
||||||
}
|
case '+':
|
||||||
if (c == '.' && data[++i] == '*')
|
case '0':
|
||||||
{
|
case '#':
|
||||||
idx++;
|
case ' ':
|
||||||
|
if (++i == len) goto UNEXPECTED_END;
|
||||||
|
c = data[i];
|
||||||
|
goto NEXT_FLAG;
|
||||||
|
case '%':
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
if (idx == vacount) goto TOO_FEW_ARGUMENTS;
|
||||||
expr = vaargs[idx];
|
expr = vaargs[idx];
|
||||||
assert(expr->expr_kind == EXPR_MAKE_ANY);
|
assert(expr->expr_kind == EXPR_MAKE_ANY);
|
||||||
Type *type = expr->make_any_expr.typeid->const_expr.typeid;
|
Type *type = expr->make_any_expr.typeid->const_expr.typeid;
|
||||||
type = type_flatten(type);
|
type = type_flatten(type);
|
||||||
while (true)
|
|
||||||
|
// Possible variable width
|
||||||
|
if (c == '*')
|
||||||
{
|
{
|
||||||
switch (c)
|
if (!type_is_integer(type))
|
||||||
{
|
{
|
||||||
case 's':
|
RETURN_SEMA_ERROR(vaargs[idx], "Expected an integer for the format width.");
|
||||||
goto NEXT;
|
|
||||||
case 'c':
|
|
||||||
if (!type_is_integer(type))
|
|
||||||
{
|
|
||||||
RETURN_SEMA_ERROR(vaargs[idx], "Expected an integer here.");
|
|
||||||
}
|
|
||||||
goto NEXT;
|
|
||||||
case 'd':
|
|
||||||
case 'X':
|
|
||||||
case 'x':
|
|
||||||
case 'B':
|
|
||||||
case 'b':
|
|
||||||
case 'o':
|
|
||||||
case 'a':
|
|
||||||
case 'A':
|
|
||||||
case 'F':
|
|
||||||
case 'f':
|
|
||||||
case 'e':
|
|
||||||
case 'E':
|
|
||||||
case 'g':
|
|
||||||
case 'G':
|
|
||||||
if (!type_is_number_or_bool(type) && !type_is_pointer_type(type))
|
|
||||||
{
|
|
||||||
if (type->type_kind == TYPE_ENUM)
|
|
||||||
{
|
|
||||||
RETURN_SEMA_ERROR(vaargs[idx], "An enum cannot directly be turned into a number. Use '.ordinal' to convert it to its value.", type_quoted_error_string(type));
|
|
||||||
}
|
|
||||||
RETURN_SEMA_ERROR(vaargs[idx], "Expected a number here, but was %s", type_quoted_error_string(type));
|
|
||||||
}
|
|
||||||
goto NEXT;
|
|
||||||
case 'p':
|
|
||||||
if (!type_is_pointer_type(type) && !type_is_integer(type))
|
|
||||||
{
|
|
||||||
RETURN_SEMA_ERROR(vaargs[idx], "Expected a pointer here.");
|
|
||||||
}
|
|
||||||
goto NEXT;
|
|
||||||
case 'H':
|
|
||||||
case 'h':
|
|
||||||
if (!type_flat_is_char_array(type))
|
|
||||||
{
|
|
||||||
RETURN_SEMA_ERROR(vaargs[idx], "Expected a char array here.");
|
|
||||||
}
|
|
||||||
goto NEXT;
|
|
||||||
case '\0':
|
|
||||||
goto DONE;
|
|
||||||
case '+':
|
|
||||||
case '-':
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
c = data[++i];
|
if (++i == len) goto UNEXPECTED_END;
|
||||||
|
c = data[i];
|
||||||
|
if (++idx == vacount) goto TOO_FEW_ARGUMENTS;
|
||||||
|
expr = vaargs[idx];
|
||||||
|
assert(expr->expr_kind == EXPR_MAKE_ANY);
|
||||||
|
type = expr->make_any_expr.typeid->const_expr.typeid;
|
||||||
|
type = type_flatten(type);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (char_is_digit(c))
|
||||||
|
{
|
||||||
|
if (++i == len) goto UNEXPECTED_END;
|
||||||
|
c = data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == '.')
|
||||||
|
{
|
||||||
|
if (++i == len) goto UNEXPECTED_END;
|
||||||
|
c = data[i];
|
||||||
|
if (c == '*')
|
||||||
|
{
|
||||||
|
if (!type_is_integer(type))
|
||||||
|
{
|
||||||
|
RETURN_SEMA_ERROR(vaargs[idx], "Expected an integer for the format width.");
|
||||||
|
}
|
||||||
|
if (++i == len) goto UNEXPECTED_END;
|
||||||
|
c = data[i];
|
||||||
|
if (++idx == vacount) goto TOO_FEW_ARGUMENTS;
|
||||||
|
expr = vaargs[idx];
|
||||||
|
assert(expr->expr_kind == EXPR_MAKE_ANY);
|
||||||
|
type = expr->make_any_expr.typeid->const_expr.typeid;
|
||||||
|
type = type_flatten(type);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!char_is_digit(c))
|
||||||
|
{
|
||||||
|
RETURN_SEMA_ERROR(actual_args[format_index], "Expected a format width or '*' in the format string but got another character");
|
||||||
|
}
|
||||||
|
while (char_is_digit(c))
|
||||||
|
{
|
||||||
|
if (++i == len) goto UNEXPECTED_END;
|
||||||
|
c = data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 's':
|
||||||
|
goto NEXT;
|
||||||
|
case 'c':
|
||||||
|
if (!type_is_integer(type))
|
||||||
|
{
|
||||||
|
RETURN_SEMA_ERROR(vaargs[idx], "Expected an integer here.");
|
||||||
|
}
|
||||||
|
goto NEXT;
|
||||||
|
case 'd':
|
||||||
|
case 'X':
|
||||||
|
case 'x':
|
||||||
|
case 'B':
|
||||||
|
case 'b':
|
||||||
|
case 'o':
|
||||||
|
case 'a':
|
||||||
|
case 'A':
|
||||||
|
case 'F':
|
||||||
|
case 'f':
|
||||||
|
case 'e':
|
||||||
|
case 'E':
|
||||||
|
case 'g':
|
||||||
|
case 'G':
|
||||||
|
if (!type_is_number_or_bool(type) && !type_is_pointer_type(type))
|
||||||
|
{
|
||||||
|
if (type->type_kind == TYPE_ENUM)
|
||||||
|
{
|
||||||
|
RETURN_SEMA_ERROR(vaargs[idx], "An enum cannot directly be turned into a number. Use '.ordinal' to convert it to its value.", type_quoted_error_string(type));
|
||||||
|
}
|
||||||
|
RETURN_SEMA_ERROR(vaargs[idx], "Expected a number here, but was %s", type_quoted_error_string(type));
|
||||||
|
}
|
||||||
|
goto NEXT;
|
||||||
|
case 'p':
|
||||||
|
if (!type_is_pointer_type(type) && !type_is_integer(type))
|
||||||
|
{
|
||||||
|
RETURN_SEMA_ERROR(vaargs[idx], "Expected a pointer here.");
|
||||||
|
}
|
||||||
|
goto NEXT;
|
||||||
|
case 'H':
|
||||||
|
case 'h':
|
||||||
|
if (!type_flat_is_char_array(type))
|
||||||
|
{
|
||||||
|
RETURN_SEMA_ERROR(vaargs[idx], "Expected a char array here.");
|
||||||
|
}
|
||||||
|
goto NEXT;
|
||||||
|
default:
|
||||||
|
if (c > 31 && c < 127)
|
||||||
|
{
|
||||||
|
RETURN_SEMA_ERROR(actual_args[format_index], "Unexpected character '%c' in format declaration.", c);
|
||||||
|
}
|
||||||
|
RETURN_SEMA_ERROR(actual_args[format_index], "Unexpected character in format declaration.", c);
|
||||||
}
|
}
|
||||||
NEXT:
|
NEXT:
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
DONE:
|
|
||||||
if (idx < vacount)
|
if (idx < vacount)
|
||||||
{
|
{
|
||||||
RETURN_SEMA_FUNC_ERROR(callee->definition, call, "Too many arguments were provided for the formatting string.");
|
RETURN_SEMA_FUNC_ERROR(callee->definition, call, "Too many arguments were provided for the formatting string.");
|
||||||
@@ -1992,6 +2050,10 @@ DONE:
|
|||||||
NO_MATCH_REF:
|
NO_MATCH_REF:
|
||||||
*no_match_ref = true;
|
*no_match_ref = true;
|
||||||
return false;
|
return false;
|
||||||
|
UNEXPECTED_END:
|
||||||
|
RETURN_SEMA_FUNC_ERROR(callee->definition, call, "Unexpected end of formatting string mid format declaration.");
|
||||||
|
TOO_FEW_ARGUMENTS:
|
||||||
|
RETURN_SEMA_FUNC_ERROR(callee->definition, call, "Too few arguments provided for the formatting string.");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool sema_call_check_contract_param_match(SemaContext *context, Decl *param, Expr *expr)
|
static inline bool sema_call_check_contract_param_match(SemaContext *context, Decl *param, Expr *expr)
|
||||||
|
|||||||
6
test/test_suite/attributes/format_fix_2199.c3
Normal file
6
test/test_suite/attributes/format_fix_2199.c3
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import std;
|
||||||
|
fn void main()
|
||||||
|
{
|
||||||
|
io::printfn("%*d", 4, 4);
|
||||||
|
io::printfn("%.*0s", 5, "123"); // #error: Unexpected character '0' in format declaration
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user