diff --git a/common/build_target.c2 b/common/build_target.c2 index d8533fa1..e4c015cc 100644 --- a/common/build_target.c2 +++ b/common/build_target.c2 @@ -201,6 +201,7 @@ public fn void Target.disableWarnings(Target* t) { t.warnings.no_unreachable_code = true; t.warnings.no_unknown_attribute = true; t.warnings.no_deprecated = true; + t.warnings.no_max_identifier_length = true; } public fn void Target.enableWarnings(Target* t) { @@ -217,6 +218,7 @@ public fn void Target.enableWarnings(Target* t) { t.warnings.no_unreachable_code = false; t.warnings.no_unknown_attribute = false; t.warnings.no_deprecated = 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 316aedee..141b773f 100644 --- a/common/warning_flags.c2 +++ b/common/warning_flags.c2 @@ -29,6 +29,7 @@ public type Flags struct { bool no_unreachable_code; bool no_unknown_attribute; bool no_deprecated; + bool no_max_identifier_length; bool are_errors; } diff --git a/compiler/c2recipe_parser.c2 b/compiler/c2recipe_parser.c2 index e42af6fa..1a2e04ec 100644 --- a/compiler/c2recipe_parser.c2 +++ b/compiler/c2recipe_parser.c2 @@ -590,6 +590,9 @@ fn void Parser.parseWarnings(Parser* p) { case "deprecated": warnings.no_deprecated = 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 c5f06db3..85613188 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; @@ -119,6 +120,7 @@ type Compiler struct { const Options* opts; // no ownership target_info.Info targetInfo; PluginHandler* pluginHandler; // no ownership + const warning_flags.Flags* warnings; // no ownership ast_context.Context* context; string_pool.Pool* astPool; @@ -182,6 +184,7 @@ fn void Compiler.build(Compiler* c, c.target = target; c.opts = opts; c.pluginHandler = pluginHandler; + c.warnings = target.getWarnings(); if (opts.bootstrap) { c.target.setBackEnd(C); @@ -199,7 +202,8 @@ fn void Compiler.build(Compiler* c, c.target.disableAsserts(); } - diags.setWarningAsError(target.getWarnings().are_errors); + diags.setWarningAsError(c.warnings.are_errors); + c.diags.clear(); c.context = ast_context.create(16*1024); @@ -215,7 +219,7 @@ fn void Compiler.build(Compiler* c, c.parse_queue.init(false, 64); - c.attr_handler = attr_handler.create(diags, target.getWarnings()); + c.attr_handler = attr_handler.create(diags, c.warnings); c.builder = ast_builder.create(c.context, diags, c.auxPool, @@ -291,6 +295,7 @@ fn void Compiler.build(Compiler* c, c.builder, &c.kwinfo, c.target.getFeatures(), + c.warnings, c.target.hasAsserts()); ast.initialize(c.context, c.astPool, c.targetInfo.intWidth / 8, color.useColor()); @@ -300,7 +305,7 @@ fn void Compiler.build(Compiler* c, c.astPool, c.builder, &c.allmodules, - c.target.getWarnings(), + c.warnings, c.target.hasAsserts(), c.opts.check_only); diff --git a/parser/c2_parser.c2 b/parser/c2_parser.c2 index b6fce041..d9c4c0c6 100644 --- a/parser/c2_parser.c2 +++ b/parser/c2_parser.c2 @@ -35,6 +35,7 @@ import value_type local; #if DumpTokens import utils; #endif +import warning_flags; import csetjmp local; import ctype local; @@ -61,6 +62,7 @@ public type Parser struct @(opaque) { Builder* builder; const string_list.List* features; const keywords.Info* kwinfo; + const warning_flags.Flags* warnings; bool is_interface; bool is_generated; bool has_asserts; @@ -86,6 +88,7 @@ public fn Parser* create(SourceMgr* sm, ast_builder.Builder* builder, const keywords.Info* kwinfo, const string_list.List* features, + const warning_flags.Flags* warnings, bool has_asserts) { Parser* p = calloc(1, sizeof(Parser)); @@ -95,6 +98,7 @@ public fn Parser* create(SourceMgr* sm, p.builder = builder; p.features = features; p.kwinfo = kwinfo; + p.warnings = warnings; p.has_asserts = has_asserts; p.va_list_idx = pool.addStr("va_list", true); p.varargs_idx = pool.addStr("varargs", true); @@ -135,6 +139,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, @@ -157,6 +162,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, Parser.on_tokenizer_error, p, false); diff --git a/parser/c2_tokenizer.c2 b/parser/c2_tokenizer.c2 index a0cef8b6..720e4107 100644 --- a/parser/c2_tokenizer.c2 +++ b/parser/c2_tokenizer.c2 @@ -24,6 +24,7 @@ import string_pool; import token local; import utf8; import value_type local; +import warning_flags; import ctype local; import stdarg local; @@ -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; + ErrorFn on_error; void* on_error_arg; @@ -278,7 +281,7 @@ public type Tokenizer struct { char[256] error_msg; } -static_assert(408, sizeof(Tokenizer)); +static_assert(416, 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, ErrorFn on_error, void* on_error_arg, bool raw_mode) @@ -300,6 +304,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_error_arg = on_error_arg; @@ -685,6 +690,15 @@ fn void Tokenizer.error(Tokenizer* t, Token* result, const char* format @(printf if (t.on_error) t.on_error(t.on_error_arg, FatalError, result.loc, t.error_msg); } +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_error) t.on_error(t.on_error_arg, Warning, loc, t.error_msg); +} + // 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; @@ -720,9 +734,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 cb981a81..3134a06b 100644 --- a/recipe.txt +++ b/recipe.txt @@ -411,6 +411,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 a23c8125..51e9035c 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 { // @warning{identifier too long (max 31 chars)} i32 x; } diff --git a/test/naming/max_identifier_var.c2 b/test/naming/max_identifier_var.c2 index 22d5e940..d35b5c24 100644 --- a/test/naming/max_identifier_var.c2 +++ b/test/naming/max_identifier_var.c2 @@ -3,6 +3,6 @@ module test; fn void test1() { i32 thirty_one_is_fine_for_a_name__; - i32 thirty_two_is_too_long_for_an_id; // @error{identifier too long (max 31 chars)} + i32 thirty_two_is_too_long_for_an_id; // @warning{identifier too long (max 31 chars)} } diff --git a/test/naming/no_max_identifier_type.c2 b/test/naming/no_max_identifier_type.c2 new file mode 100644 index 00000000..04139b7d --- /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 00000000..5a94de01 --- /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 1bfa67b5..cff8f302 100644 --- a/tools/c2cat.c2 +++ b/tools/c2cat.c2 @@ -262,7 +262,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, true); + tokenizer.init(ctx.pool, buf, ctx.input, 0, &kwinfo, &features, nil, nil, nil, true); ctx.tokenizer = &tokenizer; ctx.attr_registry.init(ctx.pool);