diff --git a/common/build_target.c2 b/common/build_target.c2 index ee3478c95..a72f46b79 100644 --- a/common/build_target.c2 +++ b/common/build_target.c2 @@ -196,6 +196,7 @@ public fn void Target.disableWarnings(Target* t) { t.warnings.no_unused_label = true; t.warnings.no_unused_enum_constant = true; t.warnings.no_unreachable_code = true; + t.warnings.no_max_identifier_length = true; } public fn void Target.enableWarnings(Target* t) { @@ -210,6 +211,7 @@ public fn void Target.enableWarnings(Target* t) { t.warnings.no_unused_label = false; t.warnings.no_unused_enum_constant = false; t.warnings.no_unreachable_code = false; + t.warnings.no_max_identifier_length = false; } public fn const warning_flags.Flags* Target.getWarnings(const Target* t) { diff --git a/common/warning_flags.c2 b/common/warning_flags.c2 index adee72ca6..e0608bc3e 100644 --- a/common/warning_flags.c2 +++ b/common/warning_flags.c2 @@ -27,6 +27,7 @@ public type Flags struct { bool no_unused_label; bool no_unused_enum_constant; bool no_unreachable_code; + bool no_max_identifier_length; bool are_errors; } diff --git a/compiler/c2recipe_parser.c2 b/compiler/c2recipe_parser.c2 index 54e51dac5..8a1afd684 100644 --- a/compiler/c2recipe_parser.c2 +++ b/compiler/c2recipe_parser.c2 @@ -580,6 +580,9 @@ fn void Parser.parseWarnings(Parser* p) { case "unreachable-code": warnings.no_unreachable_code = disable; break; + case "max-identifier-length": + warnings.no_max_identifier_length = disable; + break; case "promote-to-error": warnings.are_errors = !disable; break; diff --git a/compiler/compiler.c2 b/compiler/compiler.c2 index 773916220..b60a28041 100644 --- a/compiler/compiler.c2 +++ b/compiler/compiler.c2 @@ -40,6 +40,7 @@ import string_pool; import string_utils; import target_info; import utils; +import warning_flags; import c_errno local; import ctype; @@ -115,6 +116,7 @@ type Compiler struct { build_file.Info* build_info; // no ownership, can be nil build_target.Target* target; // no ownership const Options* opts; // no ownership + const warning_flags.Flags* warnings; // no ownership target_info.Info targetInfo; PluginHandler* pluginHandler; // no ownership @@ -180,8 +182,9 @@ fn void Compiler.build(Compiler* c, c.target = target; c.opts = opts; c.pluginHandler = pluginHandler; + c.warnings = target.getWarnings(); - diags.setWarningAsError(target.getWarnings().are_errors); + diags.setWarningAsError(c.warnings.are_errors); c.diags.clear(); c.context = ast_context.create(16*1024); @@ -270,7 +273,8 @@ fn void Compiler.build(Compiler* c, c.astPool, c.builder, &c.kwinfo, - target.getFeatures()); + target.getFeatures(), + c.warnings); ast.initialize(c.context, c.astPool, c.targetInfo.intWidth / 8, color.useColor()); @@ -279,7 +283,7 @@ fn void Compiler.build(Compiler* c, c.astPool, c.builder, &c.allmodules, - c.target.getWarnings()); + c.warnings); if (opts.show_libs) { c.showAllLibs(); diff --git a/parser/c2_parser.c2 b/parser/c2_parser.c2 index b173d3fe8..ac73c19b1 100644 --- a/parser/c2_parser.c2 +++ b/parser/c2_parser.c2 @@ -34,6 +34,7 @@ import token local; #if DumpTokens import utils; #endif +import warning_flags; import stdarg local; import stdlib local; @@ -58,8 +59,9 @@ public type Parser struct @(opaque) { diagnostics.Diags* diags; string_pool.Pool* pool; Builder* builder; - const string_list.List* features; const keywords.Info* kwinfo; + const string_list.List* features; + const warning_flags.Flags* warnings; bool is_interface; u32 va_list_idx; u32 varargs_idx; @@ -77,15 +79,17 @@ public fn Parser* create(SourceMgr* sm, string_pool.Pool* pool, ast_builder.Builder* builder, const keywords.Info* kwinfo, - const string_list.List* features) + const string_list.List* features, + const warning_flags.Flags* warnings) { Parser* p = calloc(1, sizeof(Parser)); p.sm = sm; p.diags = diags; p.pool = pool; p.builder = builder; - p.features = features; p.kwinfo = kwinfo; + p.features = features; + p.warnings = warnings; p.va_list_idx = pool.addStr("va_list", true); p.varargs_idx = pool.addStr("varargs", true); p.stdarg_idx = pool.addStr("stdarg", true); @@ -120,6 +124,7 @@ public fn void Parser.parse(Parser* p, i32 file_id, bool is_interface, bool is_g p.sm.get_offset(p.file_id), p.kwinfo, p.features, + p.warnings, nil, nil, nil, @@ -142,6 +147,7 @@ public fn void Parser.parse(Parser* p, i32 file_id, bool is_interface, bool is_g p.sm.get_offset(p.file_id), p.kwinfo, p.features, + p.warnings, on_tokenizer_error, on_tokenizer_warning, p, @@ -370,7 +376,10 @@ fn void Parser.parseTopLevel(Parser* p) { // returns if embed attribute was seen fn void Parser.parseOptionalAttributes(Parser* p) { - if (p.tok.kind != Kind.At) return; + if (p.tok.kind == Kind.At) p.parseAttributes(); +} + +fn void Parser.parseAttributes(Parser* p) { p.consumeToken(); p.expectAndConsume(Kind.LParen); diff --git a/parser/c2_tokenizer.c2 b/parser/c2_tokenizer.c2 index 6b0b7a039..2d6b8cd70 100644 --- a/parser/c2_tokenizer.c2 +++ b/parser/c2_tokenizer.c2 @@ -24,6 +24,7 @@ import string_list; import string_pool; import token local; import utf8; +import warning_flags; import string; import stdlib; @@ -265,6 +266,8 @@ public type Tokenizer struct { string_pool.Pool* pool; // no ownership string_buffer.Buf* buf; // no ownership, used for strings and character constants + const warning_flags.Flags* warnings; + HandlerFn on_error; HandlerFn on_warning; void* fn_arg; @@ -278,7 +281,7 @@ public type Tokenizer struct { char[256] error_msg; } -static_assert(416, sizeof(Tokenizer)); +static_assert(424, sizeof(Tokenizer)); public fn void Tokenizer.init(Tokenizer* t, string_pool.Pool* pool, @@ -287,6 +290,7 @@ public fn void Tokenizer.init(Tokenizer* t, SrcLoc loc_start, const keywords.Info* kwinfo, const string_list.List* features, + const warning_flags.Flags* warnings, HandlerFn on_error, HandlerFn on_warning, void* fn_arg, @@ -301,6 +305,7 @@ public fn void Tokenizer.init(Tokenizer* t, t.line_start = input; t.pool = pool; t.buf = buf; + t.warnings = warnings; t.on_error = on_error; t.on_warning = on_warning; t.fn_arg = fn_arg; @@ -687,6 +692,15 @@ fn void Tokenizer.error(Tokenizer* t, Token* result, const char* format @(printf if (t.on_error) t.on_error(t.fn_arg, result.loc); } +fn void Tokenizer.warning(Tokenizer* t, SrcLoc loc, const char* format @(printf_format), ...) { + va_list args; + va_start(args, format); + vsnprintf(t.error_msg, sizeof(t.error_msg), format, args); + va_end(args); + + if (t.on_warning) t.on_warning(t.fn_arg, loc); +} + // generate an error but keep parsing fn void Tokenizer.num_error(Tokenizer* t, Token* result, const char* p, const char* format @(printf_format), ...) { va_list args; @@ -722,9 +736,8 @@ fn void Tokenizer.lex_identifier(Tokenizer* t, Token* result) { while (Identifier_char[(u8)(*end)]) end++; usize len = (usize)(end - start); - if (len > constants.MaxIdentifierLen && !t.raw_mode) { - t.error(result, "identifier too long (max %d chars)", constants.MaxIdentifierLen); - return; + if (len > constants.MaxIdentifierLen && !t.raw_mode && t.warnings && !t.warnings.no_max_identifier_length) { + t.warning(result.loc, "identifier too long (max %d chars)", constants.MaxIdentifierLen); } t.cur += len; result.name_idx = t.pool.add(start, len, true); diff --git a/recipe.txt b/recipe.txt index ef7c1cbcd..50ae883c2 100644 --- a/recipe.txt +++ b/recipe.txt @@ -403,6 +403,7 @@ executable c2cat common/file/reader.c2 common/string_list.c2 common/utf8.c2 + common/warning_flags.c2 parser/c2_tokenizer.c2 parser/keywords.c2 diff --git a/test/naming/max_identifier_type.c2 b/test/naming/max_identifier_type.c2 index a23c8125b..fd1cd8d39 100644 --- a/test/naming/max_identifier_type.c2 +++ b/test/naming/max_identifier_type.c2 @@ -5,7 +5,7 @@ type T123456789012345678901234567890 struct { i32 x; } -type thirty_two_is_too_long_for_an_id struct { // @error{identifier too long (max 31 chars)} +type Thirty_two_is_too_long_for_an_id struct { // @error{identifier too long (max 31 chars)} i32 x; } diff --git a/test/naming/no_max_identifier_type.c2 b/test/naming/no_max_identifier_type.c2 new file mode 100644 index 000000000..04139b7d7 --- /dev/null +++ b/test/naming/no_max_identifier_type.c2 @@ -0,0 +1,12 @@ +// @warnings{no-unused} +// @warnings{no-max-identifier-length} +module test; + +type T123456789012345678901234567890 struct { + i32 x; +} + +type Very_long_type_names_are_ok_if_requested_for_specific_targets struct { + i32 x; +} + diff --git a/test/naming/no_max_identifier_var.c2 b/test/naming/no_max_identifier_var.c2 new file mode 100644 index 000000000..5a94de011 --- /dev/null +++ b/test/naming/no_max_identifier_var.c2 @@ -0,0 +1,9 @@ +// @warnings{no-unused} +// @warnings{no-max-identifier-length} +module test; + +fn void test1() { + i32 thirty_one_is_fine_for_a_name__; + i32 very_long_var_names_are_ok_if_requested_for_specific_targets; +} + diff --git a/tools/c2cat.c2 b/tools/c2cat.c2 index a2aec0a71..7bde6ce51 100644 --- a/tools/c2cat.c2 +++ b/tools/c2cat.c2 @@ -287,7 +287,7 @@ public fn i32 c2cat(const char* filename, bool use_color) keywords.Info kwinfo; kwinfo.init(ctx.pool); c2_tokenizer.Tokenizer tokenizer; - tokenizer.init(ctx.pool, buf, ctx.input, 0, &kwinfo, &features, nil, nil, nil, true); + tokenizer.init(ctx.pool, buf, ctx.input, 0, &kwinfo, &features, nil, nil, nil, nil, true); ctx.tokenizer = &tokenizer; Token tok;